Ответ
Начиная с Java 7, для этого используется конструкция try-with-resources. Она автоматически закрывает любые ресурсы, реализующие интерфейсы AutoCloseable или Closeable.
Синтаксис и пример:
try (FileInputStream fis = new FileInputStream("file.txt");
BufferedInputStream bis = new BufferedInputStream(fis)) {
// Работа с ресурсами
int data = bis.read();
} // Здесь fis и bis будут автоматически закрыты, даже если выброшено исключение
Как это работает и почему это лучше:
- Автоматическое закрытие: Компилятор генерирует блок
finally, который вызываетclose()для каждого объявленного ресурса в обратном порядке. - Подавление исключений: Если в блоке
tryи вclose()возникли исключения, исключение изtryбудет основным, а изclose()— подавленным (доступно черезThrowable.getSuppressed()). - Сравнение с ручным управлением (до Java 7):
// Старый, многословный и подверженный ошибкам способ FileInputStream fis = null; try { fis = new FileInputStream("file.txt"); // работа... } finally { if (fis != null) { try { fis.close(); // Может тоже выбросить исключение } catch (IOException e) { // Логирование, часто игнорируется } } }
Практическое правило: Всегда предпочитайте try-with-resources ручному закрытию в finally. Это делает код чище, безопаснее и предотвращает утечки ресурсов.
Ответ 18+ 🔞
А, ну вот, смотри, блядь, с седьмой джавы подвезли такую штуку — try-with-resources. Это чтоб твои ресурсы, которые AutoCloseable или Closeable, сами закрывались, как только ты с ними закончил. Не надо больше эти ебучки с finally и проверками на null писать, а то забудешь — и привет, утечка.
Вот как это выглядит, ёпта:
try (FileInputStream fis = new FileInputStream("file.txt");
BufferedInputStream bis = new BufferedInputStream(fis)) {
// Тут работаешь с ними, как обычно
int data = bis.read();
} // А тут — магия! fis и bis закроются сами, даже если всё полетело в пизду с исключением.
А теперь, сука, почему это овердохуище удобнее:
- Закрывается само. Компилятор, хитрая жопа, сам сгенерирует невидимый
finally, который вызоветclose()на всех ресурсах, да ещё и в правильном порядке — с конца. - Исключения не теряются. Если и в основном коде, и при закрытии что-то пошло не так, то исключение из
tryбудет главным, а то, что изclose(), — прицепом (достать его можно черезThrowable.getSuppressed()). Раньше же второе просто затирало первое, и ты нихуя не понимал, где изначально косяк. - Сравни с тем, как было раньше, до Java 7, ебать мои старые костыли:
// Старый способ — много кода, и всё можно запороть FileInputStream fis = null; try { fis = new FileInputStream("file.txt"); // работа... } finally { if (fis != null) { try { fis.close(); // А эта строка тоже может выкинуть исключение, блядь! } catch (IOException e) { // И его обычно просто забивали, в рот меня чих-пых } } }
Так что золотое правило, блядь: всегда юзай try-with-resources, если ресурс его поддерживает. Код в разы чище, надёжнее, и не придётся потом гадать, почему у тебя файловые дескрипторы кончились.