Какова цель инструкций 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, ваш код становится намного чище и, самое главное, ваш ресурс всегда будет закрыт :-)