Comments 15
В общем, удобство это очень субъективное и условное. Особенно, если речь идёт об изменениях в compile time. Действительно, как дебажить потом? Я бы пошёл по пути версии 2 + обёртки.
@Cleanup("free")
в try-finally с вызовом метода free. А если такого метода нет, то возникнет ошибка компиляции. Да и плагин Lombok-а к IDEA (или к Eclipse) во время написания кода подскажет, что такого метода нет.Lombok это не рефлексия, а расширение языка через annotation processors.
Код очень конкретный в силу перегруженности прямым управлением ресурсами.
Его логично разбить на методы (или классы) для получения, преобразование и записи данных, каждый из которых использует только те соединения, запросы и парсеры, какие нужны ему самому.
Конкретные фабрики ресурсов передавать из точки сборки.
Короче, использовать DI и будет вам счастье.
И да, возможности Java 8 смотрятся намного лучше магических аннотаций, совершенно непонятно, что там такого ужасного для автора.
Ужасного там то, что он работает только на Java 8
Если у проекта нет требования совместимости с ранними версиями, то какая разница?
появляется какая-то магическая переменная fake
Это не магия, а полноценная часть языка. И ответственность данной переменной простая и понятная — дать возможность очистки для объекта, которые не умеет делать это самостоятельно. Хотя, конечно, приятнее было бы оставить просто выражение.
А вот специальные атрибуты, повязанные на конкретную библиотеку — самая что ни на есть магия со всеми вытекающими.
try {
... открывает ресурс ...
} finally {
... правильно закрываем ресурс, если он не null ...
}
Все остальные варианты — это костыли (за исключением обертки, но ее писать не удобно). И @Cleanup — это аннотация, которая помогает сделать более менее красивый костыль. Переменная fake и использование передачи метода, чтобы только закрыть ресурс — она просто ужасна:
Resource res; // вот тут она объявляется только потому, что внутри try ее не объявить - это жесть №1
try (Autoclose fake = (res = ResourceCreator.create())::free) { // все, fakе больше нигде не используется, это жесть №2
... тут уже полезный код ...
}
Я же не говорю, что давайте использовать @Cleanup везде, нет. Если метод маленький и там один такой ресурс с free, то не беда, давайте просто try-finally сделаем. Но когда идет работа с потоками, один вкладывается в другой, разные врайтеры, которые не закрывают ресурсы, когда закрываются сами, и если их много, то почему нет? Имхо одна строчка
@Cleanup("free") Resource = ...
куда понятнее и более читаемая.
В данном случае единственным бескостыльным методом является
Вы считаете бескостыльным только явное?
Здесь с вами многие не согласятся.
Лично я полагаю, что шаблонный код должен быть как можно меньше. Это позволяет при чтении сосредоточиться на реализованном алгоритме вместо шума.
Переменная fake и использование передачи метода, чтобы только закрыть ресурс — она просто ужасна
Переменная, когда достаточно выражения, действительно смотрится не очень красиво. Но таких мест в яве много, для тех кому нестерпимо — есть скала, котлин и прочие языки для JVM.
Полагаю, что эффект можно смягчить с помощью обобщенной обертки, параметризованной типом содержимого и методом очистки. Тогда переменная останется только одна.
Что до использования передачи метода — это заведомо лучше атрибута со строковым параметром.
- Я тоже за использование шаблонного кода как можно меньше.
- Ничего плохого в строкового имени метода для этапа компиляции нет.
- Приведите код шаблонной обертки.
Ничего плохого в строкового имени метода для этапа компиляции нет.
Тут я с вами не согласен. Я очень уважаю инструменты для вплетения кода, но предпочитаю без крайней нужды не использовать имена программных объектов как строковые константы.
Приведите код шаблонной обертки
import java.lang.*;
import java.util.function.Function;
public final class Usable<T> implements AutoCloseable
{
public Usable(T object, Function<T, AutoCloseable> toCloseable)
{
_object = object;
_closeable = toCloseable.apply(object);
}
public static <T> Usable from(T object, Function<T, AutoCloseable> toCloseable)
{
return new Usable<T>(object, toCloseable);
}
public T getObject()
{
return _object;
}
public void close() throws Exception
{
_closeable.close();
}
private AutoCloseable _closeable;
private T _object;
}
Прошу извинить если коряво — я на яве не пишу совсем, по ссылке онлайн-демка.
Работа с ресурсами, или как я пропихивал @Cleanup