Как работает конструкция try-with-resources в Java?

Ответ

Try-with-resources — это конструкция, введенная в Java 7 для автоматического управления ресурсами, которые необходимо закрывать после использования (например, потоки ввода-вывода, соединения с БД).

Принцип работы: Ресурс, объявленный в круглых скобках после try, должен реализовывать интерфейс java.lang.AutoCloseable. После завершения блока try (нормального или из-за исключения) JVM автоматически вызывает метод close() каждого ресурса.

Преимущества перед try-catch-finally:

  • Код становится короче и чище.
  • Исключения не "маскируются". Если в блоке try и в close() возникли исключения, исключение из try передается вызывающему коду, а исключение из close() добавляется к нему как suppressed (доступно через Throwable.getSuppressed()).

Синтаксис и пример:

import java.io.*;

public class TryWithResourcesDemo {
    public static void main(String[] args) {
        // Ресурсы объявляются в скобках. Они будут закрыты в обратном порядке.
        try (FileInputStream fis = new FileInputStream("input.txt");
             BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {

            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            // Здесь автоматически вызывается reader.close(), затем fis.close()
        } catch (IOException e) { // Ловим возможные исключения
            System.err.println("Ошибка при работе с файлом: " + e.getMessage());
        }
        // Ресурсы уже закрыты, даже если было исключение.
    }
}

Важно: Начиная с Java 9, ресурсы можно объявлять вне блока try, если они являются effectively final.

BufferedReader reader = new BufferedReader(...);
try (reader) { // Допустимо в Java 9+
    // использование reader
}

Ответ 18+ 🔞

А, слушай, вот эта штука — try-with-resources. Её, блядь, в Java 7 подкинули, чтобы народ перестал, как обезьяна, вручную всё закрывать. Ну ты знаешь, эти твои FileInputStream, Connection — открыл, поработал, а потом обязательно надо close() позвать, иначе ресурсы повиснут, и приложение твоё, как маньяк в тупике, начнёт жрать память до полного пиздеца.

Как оно, сука, работает? Всё просто, как три копейки. Ты в круглых скобках после try объявляешь свой ресурс. Главное, чтобы этот ресурс был не левый, а реализовывал интерфейс AutoCloseable. А потом, когда блок try закончится — неважно, нормально или потому что всё полетело к чертям — JVM сама, по-тихому, вызовет для каждого ресурса метод close(). Красота, ёпта!

И чем это лучше старого доброго try-catch-finally? Да всем, блядь!

  • Код в разы короче. Не надо этих танцев с бубном, где в finally ты ещё раз оборачиваешь close() в try-catch, а то вдруг и он выбросит исключение. Пиздец, а не код.
  • Исключения не теряются. Раньше была беда: если в блоке try вылетело исключение, а потом в finally при закрытии — ещё одно, то первое просто нахуй пропадало, затиралось вторым. А тут — нет, блядь! Исключение из try остаётся главным, а то, что вылетело в close(), цепляется к нему как suppressed (дополненное). Достать его можно через getSuppressed(). Честно и прозрачно, как слеза младенца, блядь.

Смотри, как это выглядит на практике:

import java.io.*;

public class TryWithResourcesDemo {
    public static void main(String[] args) {
        // Вот тут, в скобках, объявляем всё, что надо будет закрыть. Порядок закрытия — обратный объявлению.
        try (FileInputStream fis = new FileInputStream("input.txt");
             BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {

            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            // Тут, за кулисами, вызовутся reader.close(), а потом fis.close(). Автоматом, блядь!
        } catch (IOException e) { // Ловим всё, что могло пойти не так
            System.err.println("Ошибка при работе с файлом: " + e.getMessage());
        }
        // И не надо париться — ресурсы уже закрыты, даже если выше всё взорвалось.
    }
}

А ещё, блядь, с Java 9 стало ещё проще! Если твой ресурс уже объявлен как effectively final (то есть не меняется), то его можно просто вписать в try:

BufferedReader reader = new BufferedReader(...);
try (reader) { // Да, вот так, ёбана! Работает с девятки.
    // Юзаем reader на всю катушку
}
// И он всё равно закроется. Волшебство, пиздец!

Вот и вся магия. Перестань быть распиздяем и пиши finally на десять строк — используй нормальные инструменты, блядь.