Разработка - сложная штука 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 = …;В java 9 в блок try можно передать переменные:
Selector selector = …) {
// …
}
DatagramChannel udpServer = …;С одной стороны это удобно. Код выглядит приятно.
Selector selector = …;
try (udpServer;selector) {
// …
}
С другой - после try остаются переменные с закрытыми ресурсами. Теперь нельзя сказать, что java реализует RAII.
Ну и ладно, никто не расстроился🙂 Языки разные, и классно замечать, как по-разному в них реализуются идеи, и как они меняются с течением времени.