Подтвердить что ты не робот

Использует 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, чтобы сделать мой вопрос понятным с каким-то примером. Очевидно, это не настоящий код!:)

4b9b3361

Ответ 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 с этим флагом, при необходимости вызывая соответствующие исключения.