Вопрос-ответ

What's the purpose of try-with-resources statements?

Какова цель инструкций try-with-resources?

В Java 7 появилась новая функция под названием try-with-resources. Что это? Почему и где мы должны ее использовать и где мы можем воспользоваться преимуществами этой функции?

В try инструкции нет catch блока, который меня смущает.

Переведено автоматически
Ответ 1

Это было введено из-за того, что некоторые ресурсы, используемые в 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

Ответ 2

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


Инструкция 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 . Инструкция declaration появляется
в круглых скобках сразу после ключевого слова try . Класс
BufferedReader в Java SE 7 и более поздних версиях реализует интерфейс
java.lang.Автоматически закрываемый. Поскольку экземпляр BufferedReader
объявлен в инструкции try-with-resource , он будет закрыт
независимо от того, завершается ли инструкция try обычным образом или внезапно


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

Ответ 3

Обновление от 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
}

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

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 . Единственное ограничение заключается в том, что переменная reader должна быть фактически final или просто final.

Ответ 4

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


  • Вам нужно будет проверить, работает ли ваш ресурс null перед его закрытием

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

  • Программисты, как правило, забывают закрыть свои ресурсы

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

java