Try with resources android

The try-with-resources Statement

The try -with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try -with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable , which includes all objects which implement java.io.Closeable , can be used as a resource.

The following example reads the first line from a file. It uses an instance of BufferedReader to read data from the file. BufferedReader is a resource that must be closed after the program is finished with it:

In this example, the resource declared in the try -with-resources statement is a BufferedReader . The declaration statement appears within parentheses immediately after the try keyword. The class BufferedReader , in Java SE 7 and later, implements the interface java.lang.AutoCloseable . Because the BufferedReader instance is declared in a try -with-resource statement, it will be closed regardless of whether the try statement completes normally or abruptly (as a result of the method BufferedReader.readLine throwing an IOException ).

Prior to Java SE 7, you can use a finally block to ensure that a resource is closed regardless of whether the try statement completes normally or abruptly. The following example uses a finally block instead of a try -with-resources statement:

However, in this example, if the methods readLine and close both throw exceptions, then the method readFirstLineFromFileWithFinallyBlock throws the exception thrown from the finally block; the exception thrown from the try block is suppressed. In contrast, in the example readFirstLineFromFile , if exceptions are thrown from both the try block and the try -with-resources statement, then the method readFirstLineFromFile throws the exception thrown from the try block; the exception thrown from the try -with-resources block is suppressed. In Java SE 7 and later, you can retrieve suppressed exceptions; see the section Suppressed Exceptions for more information.

You may declare one or more resources in a try -with-resources statement. The following example retrieves the names of the files packaged in the zip file zipFileName and creates a text file that contains the names of these files:

In this example, the try -with-resources statement contains two declarations that are separated by a semicolon: ZipFile and BufferedWriter . When the block of code that directly follows it terminates, either normally or because of an exception, the close methods of the BufferedWriter and ZipFile objects are automatically called in this order. Note that the close methods of resources are called in the opposite order of their creation.

The following example uses a try -with-resources statement to automatically close a java.sql.Statement object:

The resource java.sql.Statement used in this example is part of the JDBC 4.1 and later API.

Note: A try -with-resources statement can have catch and finally blocks just like an ordinary try statement. In a try -with-resources statement, any catch or finally block is run after the resources declared have been closed.

Suppressed Exceptions

An exception can be thrown from the block of code associated with the try -with-resources statement. In the example writeToFileZipFileContents , an exception can be thrown from the try block, and up to two exceptions can be thrown from the try -with-resources statement when it tries to close the ZipFile and BufferedWriter objects. If an exception is thrown from the try block and one or more exceptions are thrown from the try -with-resources statement, then those exceptions thrown from the try -with-resources statement are suppressed, and the exception thrown by the block is the one that is thrown by the writeToFileZipFileContents method. You can retrieve these suppressed exceptions by calling the Throwable.getSuppressed method from the exception thrown by the try block.

Читайте также:  Как создавать иконки для андроида

Classes That Implement the AutoCloseable or Closeable Interface

See the Javadoc of the AutoCloseable and Closeable interfaces for a list of classes that implement either of these interfaces. The Closeable interface extends the AutoCloseable interface. The close method of the Closeable interface throws exceptions of type IOException while the close method of the AutoCloseable interface throws exceptions of type Exception . Consequently, subclasses of the AutoCloseable interface can override this behavior of the close method to throw specialized exceptions, such as IOException , or no exception at all.

Источник

Инструкция try-with-resources в Java

Автор: Olivera Popović
Дата записи

Вступление

try-with-resources является одним из нескольких операторов try в Java, направленных на освобождение разработчиков от обязанности освобождать ресурсы, используемые в блоке try .

Изначально он был представлен в Java 7, и вся идея заключалась в том, что разработчику не нужно беспокоиться об управлении ресурсами для ресурсов, которые они используют только в одном try-catch-finally блоке. Это достигается за счет устранения необходимости в блоках finally , которые разработчики использовали только для закрытия ресурсов на практике.

Кроме того, код, использующий try-with-resources , часто является более чистым и читаемым, что облегчает управление кодом, особенно когда мы имеем дело со многими блоками try .

Синтаксис

Синтаксис try-with-resources почти идентичен обычному синтаксису try-catch-finally . Единственное различие-это скобки после try , в которых мы объявляем, какие ресурсы мы будем использовать:

Тот же код, написанный с использованием try-with-resources , будет выглядеть следующим образом:

То, как Java понимает этот код:

Ресурсы, открытые в скобках после оператора try , понадобятся только здесь и сейчас. Я вызову их методы .close () , как только закончу работу в блоке try . Если в блоке try возникнет исключение, я все равно закрою эти ресурсы.

До внедрения этого подхода закрытие ресурсов выполнялось вручную, как показано в предыдущем коде. По сути, это был стандартный код, и базы кода были завалены ими, что снижало читаемость и затрудняло их обслуживание.

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

Примечание : Начиная с Java 9, нет необходимости объявлять ресурсы в инструкции try-with-resources . Вместо этого мы можем сделать что-то подобное:

Множество Ресурсов

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

Если бы мы хотели работать с несколькими файлами, мы бы открыли файлы в инструкции try() и разделили их точкой с запятой:

Затем Java позаботится о том, чтобы вызвать .close() на всех ресурсах, которые мы открыли в try() .

Примечание : Они закрываются в обратном порядке объявления, что означает, что в нашем примере сканер будет закрыт перед автором .

Поддерживаемые Классы

Все ресурсы, объявленные в try () , должны реализовывать Автоклавируемый интерфейс. Обычно это различные типы устройств записи, считывателей, сокетов, потоков вывода или ввода и т. Д. Все, что вам нужно будет написать resource.close() после того, как вы закончите с ним работать.

Читайте также:  Тайм менеджмент для андроида

Это, конечно, включает в себя определенные пользователем объекты, реализующие Автоклавируемый интерфейс. Однако вы редко столкнетесь с ситуацией, когда захотите написать свои собственные ресурсы.

В случае, если это произойдет, вам необходимо реализовать Автоклавируемый или Закрываемый (только там, чтобы сохранить обратную совместимость, предпочитайте Автоклавируемый ) интерфейс и переопределить метод .close() :

Обработка исключений

Если исключение создается из блока Java try-with-resources , любой ресурс, открытый в круглых скобках блока try , все равно будет автоматически закрыт.

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

Представьте себе ситуацию:

  • По какой-то причине в блоке try-with-resources возникает исключение
  • Java останавливает выполнение в блоке try-with-resources и вызывает .close() для всех ресурсов, объявленных в try()
  • Один из методов .close() создает исключение
  • Какое исключение будет “ловить” блок catch ?

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

Эти исключения являются исключениями, которые встречаются в методах .close () , и доступ к ним осуществляется иначе, чем к “обычным” исключениям.

Важно понимать, что порядок исполнения:

  1. попробуйте-с-ресурсами заблокировать
  2. неявное, наконец
  3. блок catch (если в [1] и/или [2] было выдано исключение)
  4. (явно) наконец

Например, вот ресурс, который ничего не делает, кроме как создает исключения:

Git Essentials

Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!

Этот код доступен для выполнения. Вы можете использовать его для экспериментов с использованием нескольких объектов MyResource или просмотра того, что происходит, когда try-with-resources не создает исключения, но .close() создает.

Подсказка : Внезапно исключения, возникающие при закрытии ресурсов, становятся важными.

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

Еще один факт, который следует отметить, заключается в том, что в ситуации, когда блок try не создает исключения и когда при попытке .закрыть() используемые ресурсы возникает несколько исключений, первое исключение будет распространяться по стеку вызовов, в то время как остальные будут подавлены.

Как вы можете видеть в коде, вы можете получить список всех подавленных исключений, обратившись к массиву Throwable , возвращаемому Throwable.getSuppressed() .

Помните, что внутри блока try может быть создано только одно исключение. Как только возникает исключение, код блока try завершается, и Java пытается закрыть ресурсы.

Вывод

попробуйте-с-ресурсами следует использовать вместо обычного попробуйте-поймайте-наконец , когда это возможно. Легко забыть закрыть один из ваших ресурсов после нескольких часов кодирования или забыть закрыть ресурс, который вы только что добавили в свою программу, после случайного порыва вдохновения.

Код более читабелен, его легче изменять и поддерживать, и обычно он короче.

Источник

Правильно освобождаем ресурсы в Java

Неправильное освобождение ресурсов — одна из наиболее часто допускаемых ошибок среди Java-программистов. Под ресурсом в данной статье я буду подразумевать всё, что реализует интерфейс java.io.Closeable . Итак, сразу к делу.

Будем рассматривать на примере OutputStream . Задача: получить на вход OutputStream , сделать некоторую полезную работу с ним, закрыть OutputStream .

Неправильное решение №1

Данное решение опасно, потому что если в коде сгенерируется исключение, то stream.close() не будет вызван. Произойдет утечка ресурса (не закроется соединение, не будет освобожден файловый дескриптор и т.д.)

Читайте также:  Автономный будильник для андроид

Неправильное решение №2

Попробуем исправить предыдущий код. Используем try-finally :

Теперь close() всегда будет вызываться (ибо finally ): ресурс в любом случае будет освобождён. Вроде всё правильно. Ведь так?

Проблема следующая. Метод close() может сгенерировать исключение. И если при этом основной код работы с ресурсом тоже выбросит исключение, то оно перезатрется исключением из close() . Информация об исходной ошибке пропадёт: мы никогда не узнаем, что было причиной исходного исключения.

Неправильное решение №3

Попробуем исправить ситуацию. Если stream.close() может затереть «главное» исключение, то давайте просто «проглотим» исключение из close() :

Теперь вроде всё хорошо. Можем идти пить чай.

Как бы не так. Это решение ещё хуже предыдущего. Почему?

Потому что мы просто взяли и проглотили исключение из close() . Допустим, что outputStream — это FileOutputStream , обёрнутый в BufferedOutputStream . Так как BufferedOutputStream делает flush() на низлежащий поток порциями, то есть вероятность, что он его вызовет во время вызова close() . Теперь представим, что файл, в который мы пишем, заблокирован. Тогда метод close() выбросит IOException , которое будет успешно «съедено». Ни одного байта пользовательских данных не записались в файл, и мы ничего об этом не узнали. Информация утеряна.

Если сравнить это решение с предыдущим, то там мы хотя бы узнаем, что произошло что-то плохое. Здесь же вся информация об ошибке пропадает.

Замечание: если вместо OutputStream используется InputStream , то такой код имеет право на жизнь. Дело в том, что если в InputStream.close() выбрасывается исключение, то (скорее всего) никаких плохих последствий не будет, так как мы уже считали с этого потока всё что хотели. Это означает, что InputStream и OutputStream имеют совершенно разную семантику.

Неидеальное решение

Итак, как же всё-таки правильно выглядит код обработки ресурса?

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

Минусы такого решения очевидны: громоздко и сложно. Кроме того, пропадает информация об исключении из close() , если основной код выбрасывает исключение. Также openOutputStream() может вернуть null , и тогда вылетит NullPointerException (решается добавлением еще одного if’а, что приводит к ещё более громоздкому коду). Наконец, если у нас будет два ресурса (например, InputStream и OutputStream ) и более, то код просто будет невыносимо сложным.

Правильное решение (Java 7)

В Java 7 появилась конструкция try-with-resources . Используем её:

Если исключение будет выброшено в основном коде и в методе close() , то приоритетнее будет первое исключение, а второе исключение будет подавлено, но информация о нем сохранится (с помощью метода Throwable.addSuppressed(Throwable exception) , который вызывается неявно Java компилятором):

Правильное решение (Java 6 с использованием Google Guava)

В Java 6 средствами одной лишь стандартной библиотеки не обойтись. Однако нам на помощь приходит замечательная библиотека Google Guava. В Guava 14.0 появился класс com.google.common.io.Closer ( try-with-resources для бедных), с помощью которого неидеальное решение выше можно заметно упростить:

Решение заметно длиннее, чем в случае Java 7, но всё же намного короче неидеального решения. Вывод будет примерно таким же, как Java 7.

Closer также поддерживает произвольное количество ресурсов в нём (метод register(. ) ). К сожалению, Closer — это класс, помеченный аннотацией @Beta , а значит может подвергнуться значительным изменениям в будущих версиях библиотеки (вплоть до удаления).

Выводы

Правильно освобождать ресурсы не так просто, как кажется (просто только в Java 7). Всегда уделяйте этому должное внимание. InputStream и OutputStream ( Reader и Writer ) обрабатываются по-разному (по крайней мере в Java 6)!

В следующий раз я планирую рассказать, как бороться с NullPointerException .

Источник

Оцените статью