Java7 попробуй с ресурсами Преимущество оператора

Я искал новую функцию Java7. Я нашел один из них - " Попробуй с ресурсами". Кто-нибудь может сказать мне, что именно это означает? Почему и где мы должны его использовать и где мы можем воспользоваться этой функцией? Даже try заявление пропускает catch блок который смущает меня.

7 ответов

Решение

Он был введен из-за того, что некоторые ресурсы, используемые в Java (такие как соединения или потоки SQL), трудно обрабатывать должным образом; В качестве примера, в Java 6 для правильной обработки InputStream вы должны были сделать что-то вроде:

InputStream stream = new MyInputStream(...);
try {
    // ... use stream
} catch(IOException e) {
   // handle exception
} finally {
    try {
        if(stream != null) {
            stream.close();
        }
    } catch(IOException e) {
        // handle yet another possible exception
    }
}

Вы замечаете эту уродливую двойную попытку? теперь с помощью try-with-resources вы можете сделать это:

try (InputStream stream = new MyInputStream(...)){
    // ... use stream
} catch(IOException e) {
   // handle exception
}

и close() вызывается автоматически, если он генерирует IOException, он будет подавлен (как указано в спецификации языка Java 14.20.3). То же самое происходит для java.sql.Connection

Как указано в документации:

Оператор try-with-resources является оператором try, который объявляет один или несколько ресурсов. Ресурс - это объект, который должен быть закрыт после завершения программы. Оператор try-with-resources обеспечивает закрытие каждого ресурса в конце оператора. Любой объект, который реализует java.lang.AutoCloseable, который включает в себя все объекты, которые реализуют java.io.Closeable, может быть использован в качестве ресурса.

Следующий пример читает первую строку из файла. Он использует экземпляр BufferedReader для чтения данных из файла. BufferedReader - это ресурс, который должен быть закрыт после завершения работы программы:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

В этом примере ресурс, объявленный в операторе try-with-resources, является BufferedReader. Оператор объявления появляется в скобках сразу после ключевого слова try. Класс BufferedReader в Java SE 7 и более поздних версиях реализует интерфейс java.lang.AutoCloseable. Поскольку экземпляр BufferedReader объявлен в операторе try-with-resource, он будет закрыт независимо от того, завершается ли оператор try нормально или внезапно

Вы можете прочитать больше здесь.

Обновление с 2017 года после выхода Java 9

Теперь с Java 9 у нас есть больше синтаксического сахара, и мы можем иметь ресурс, объявленный за пределами try-catch блок, но все еще обрабатывается правильно.

Давайте возьмем для примера это Java 6 Способ обращения с ресурсом:

InputStream stream = new MyInputStream(...);
try {
    // ... use stream
} catch(IOException e) {
   // handle exception
} finally {
    try {
        if(stream != null) {
            stream.close();
        }
    } catch(IOException e) {
        // handle yet another possible exception
    }
}

Здесь мы можем заметить, что этот код невероятно уродлив, как указано в других ответах.

Таким образом, решение в Java 7 должен был представить это try-catch-with-resource:

try (InputStream stream = new MyInputStream(...)){
    // ... use stream
} catch(IOException e) {
   // handle exception
}

Эта запись, безусловно, лучше, чем предыдущая, однако у нас есть проблема. Если ресурс (в данном случаеstrem) был объявлен ранее, но мы хотим быть уверены, что он правильно обрабатывается в этом блоке, нам нужен такой прием:

InputStream stream = new MyInputStream(...)
try (InputStream stream2 = stream) {
   // do something with stream being sure that is going to be closed at the end
} catch(IOException e) {
   // handle exception
}

Мы можем заметить, что эта ситуация может быть решена только с помощью другой части кода. Вот почему в Java 9 был улучшен Try-With-Resources с введением нового синтаксиса:

InputStream stream = new MyInputStream(...)
try (stream) {
   // do something with stream being sure that is going to be closed at the end
} catch(IOException e) {
   // handle exception
}

Обратите внимание, что этот синтаксис приведет к ошибке времени компиляции для Java версии 8 или минорной

Это более "естественный" способ записи, хотя в большинстве случаев нам не нужен ресурс, выходящий за рамки блока try. Единственное ограничение заключается в том, что переменная читателя должна быть окончательной или только конечной.

В Java, если вы используете такой ресурс, как потоки ввода или вывода, вы всегда должны закрывать его после использования. Он также может генерировать исключения, поэтому он должен быть в trycatch блок. Закрытие должно быть в finally блок. Это как минимум путь до Java 7. У этого есть несколько недостатков:

  • Вы должны проверить, если ваш ресурс null перед закрытием
  • Само закрытие может генерировать исключения, поэтому ваш finally должен был содержать другой try - catch
  • Программисты, как правило, забывают закрыть свои ресурсы

В то время как первые два являются главным образом проблемами синтаксиса, последний является более критическим. Поэтому, если вы воспользуетесь оператором try-with, ваш код станет намного чище, а главное: ваш ресурс всегда будет закрыт:-)

Преимущество в том, что вам не нужно явно закрывать ресурсы, которые вы определили в инструкции try-with-resources. JVM позаботится об этом. Он автоматически закроет эти ресурсы для вас.

Обычно проблемы, с которыми сталкиваются разработчики, - это структурирование блоков try-catch-finally, потому что даже в блоке finally, где мы закрываем ресурсы, мы должны использовать try-catch. Существуют различные структуры оператора try-catch-finally, чтобы помочь решить эту проблему, но оператор try-with-resources в основном поможет вам упростить логику структуры кода.

Преимущества использования Try с ресурсами

  1. Более читаемый код и легко писать.

  2. Автоматическое управление ресурсами.

  3. Количество строк кода сокращено.

  4. Нет необходимости окончательно блокировать только для того, чтобы закрыть ресурсы.

  5. Мы можем открыть несколько ресурсов в инструкции try-with-resources через точку с запятой. Например, мы можем написать следующий код.

  6. Когда несколько ресурсов открываются в режиме try-with-resources, он закрывает их в обратном порядке, чтобы избежать проблем с зависимостями. Вы можете расширить мою программу ресурсов, чтобы доказать это.

public void sampleTryWithResource() {
            try(Connection dbCon = DriverManager.getConnection("url", "user", "password");
                    BufferedReader br = new BufferedReader(new FileReader("C://readfile/input.txt"));) {
                //...Your Business logic
            } catch (Exception e) {
                //...Exception Handling
            }
        }

Как насчет этого - если ресурс инициализируется внутри try{}, он автоматически не закрывается?

try {
            Scanner scanner = new Scanner(new File(csvFile));
            while (scanner.hasNext()) {
                 // do something
            }
            scanner.close();
        }catch(FileNotFoundException fnfe)
        {
            System.err.println(fnfe.getLocalizedMessage());
        }
Другие вопросы по тегам