2021-05-28 09:00:35
Ресурсы, идиома RAII и Java 9
Разработка - сложная штука c множеством идей и концептов. В этом посте я расскажу об идиоме RAII, разнице при работе с ресурсами в java и C++, блоке try-with-resources и изменениях java 9.
Начнём с основ. Ресурс - это сущность, для которой нужен эксклюзивный доступ. Их количество ограничено. Большинство ресурсов находятся за пределами JVM: файлы, соединения с БД, сокеты и т.д
Для корректной работы только один поток должен работать с ресурсом. Для этого нужно принять дополнительные меры. Обозначим их как "открыть" и "закрыть" ресурс:
Открыть = получить эксклюзивный доступ.
Закрыть = закончить работу. Теперь другой поток может работать с ресурсом.
Такой вот нехитрый жизненный цикл(ЖЦ).
RAII
или
Resource Acquisition Is Initialization - одна из техник по работе с ресурсами. Другое название:
SBRM - Scope-Bound Resource Management.
Суть: ассоциируем ресурс с объектом. Тогда ЖЦ ресурса совпадает с ЖЦ объекта. В идеале это выглядит так:
public void do() {
File f=new File("t.txt");
// Создаём объект File, ресурс "t.txt" теперь наш
// что-то делаем
}
// вышли из метода: объект f уже не нужен, ресурс "t.txt" освобождается
RAII легко реализовать в С++. В конструкторе пишем логику "открытия" ресурса, а в деструкторе - "закрытия". Конструктор и деструктор явно прописываются, поэтому ЖЦ объекта и ресурса под контролем.
В java так не получится. Деструктор выполнится неизвестно когда, а ресурс - штука ценная. Поэтому в java нужно явно вызвать метод закрытия. В стандартных библиотеках это
close().
В java 7 появилась специальная конструкция для ресурсов:
try (PrintWriter writer = new PrintWriter(…)) {
// что-то делаем
}
Ресурс реализует интерфейс
AutoCloseable, и после завершения блока для него вызовется
close(). try-with-resources считается java реализацией RAII.
Но такой формат не идеален. Внутри
try всегда определяется новый объект. Когда ресурсов два и больше, код становится громоздким:
try (DatagramChannel udpServer = …;
Selector selector = …) {
// …
}
В java 9 в блок
try можно передать переменные:
DatagramChannel udpServer = …;
Selector selector = …;
try (udpServer;selector) {
// …
}
С одной стороны это удобно. Код выглядит приятно.
С другой - после try остаются переменные с закрытыми ресурсами. Теперь нельзя сказать, что java реализует RAII.
Ну и ладно, никто не расстроился Языки разные, и классно замечать, как по-разному в них реализуются идеи, и как они меняются с течением времени.
1.5K views06:00