Использует try-with-resources без плохой формы экземпляра нового объекта?
Как правило, я всегда видел try-with-resources, которые были использованы для размещения экземпляра нового объекта, метод close()
которого вызывается, поскольку он выходит за пределы области видимости.
Насколько я могу судить, создание нового объекта не является требованием, и синтаксису try-with-resources просто нужна локальная переменная для вызова функции close(), когда это выходит за пределы области видимости. Поэтому вы можете использовать его для управления "сопряженными операциями", такими как выделение чего-либо из пула и обеспечение его возврата.
Например, MyHandle ниже показывает, как выпустить объединенный экземпляр, когда он вам больше не нужен:
// init
class MyHandle implements AutoCloseable {
boolean inUse = false;
public MyHandle allocate() {
inUse = true;
return this;
}
public void close() {
inUse = false;
}
}
MyHandle[] pool = new MyHandle[POOL_SIZE];
for (int i = 0; i < pool.length; i++) {
pool[i] = new MyHandle(i);
}
// allocate
MyHandle allocateFromPool() {
for (int i = 0; i < pool.length; i++) {
if (!pool[i].inUse)
return pool[i].allocate();
}
throw new Exception("pool depleted");
}
// using resources from the pool
try (MyHandle handle = allocateFromPool()) {
// do something
}
// at this point, inUse==false for that handle...
Является ли это плохой формой?
EDIT: Думаю, я спрашиваю, есть ли альтернативы построению такой логики или если есть какой-то главный недостаток, когда вы идете с подходом выше. Я считаю, что использование этого в библиотеке делает для чистого API.
РЕДАКТИРОВАТЬ 2: Пожалуйста, игнорируйте проблемы в примере кода, я написал его inline в текстовом поле SO, чтобы сделать мой вопрос понятным с каким-то примером. Очевидно, это не настоящий код!:)
Ответы
Ответ 1
Синтаксис try-with-resource предназначен для синтаксического сахарирования, чтобы вы могли убедиться, что вы удаляете объект, независимо от логики удаления. В вашем случае он возвращает объект в пул. Нет ничего плохого в использовании try-with-resource, как это. Это может быть не самая распространенная для него, но определенно допустимая.
Ответ 2
Под обложками большинство ресурсов (например, файловые дескрипторы) эффективно распределяются из пула операционной системой и затем возвращаются в пул при закрытии.
Использование try-with-resources таким образом совершенно справедливо.
N.B. ваш пример кода имеет значительные проблемы с потоками, но я предполагаю, что необходимая безопасность потока была удалена для ясности в вопросе. Я упоминаю это только потому, что люди НЕ должны копировать ваш код и использовать его в реализации.
Ответ 3
Ничего страшного в подобных ресурсах. Но в вашем случае я буду беспокоиться о повторном использовании закрытых ручек, которые были повторно открыты из другого потока.
Небольшая косвенность решит эту проблему, верните MyHandleWrapper
вместо прямого доступа к MyHandle
(allocateFromPool вернет новый экземпляр MyHandleWrapper). Он будет не! решить все другие проблемы с потоками.
public class MyHandleWrapper extends MyHandle {
private MyHandle handle;
private boolean closed;
public void close() {
if(!closed){
handle.inUse = false;
}
closed = true;
}
public void read() {
if (closed) {
throw new IllegalStateException("Already closed");
}
handle.read();
}
}
В основном вы сохраняете информацию, если ручка была закрыта в MyHandleWrapper. Вы защищаете любое состояние, меняя доступ к handle
с этим флагом, при необходимости вызывая соответствующие исключения.