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 FileReader and BufferedReader to read data from the file. FileReader and BufferedReader are resources that must be closed after the program is finished with it:
In this example, the resources declared in the try -with-resources statement are a FileReader and a BufferedReader . The declaration statements of these resources appear within parentheses immediately after the try keyword. The classes FileReader and BufferedReader , in Java SE 7 and later, implement the interface java.lang.AutoCloseable . Because the FileReader and BufferedReader instances are declared in a try -with-resource statement, they 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, this example might have a resource leak. A program has to do more than rely on the garbage collector (GC) to reclaim a resource’s memory when it’s finished with it. The program must also release the resoure back to the operating system, typically by calling the resource’s close method. However, if a program fails to do this before the GC reclaims the resource, then the information needed to release the resource is lost. The resource, which is still considered by the operaing system to be in use, has leaked.
In this example, if the readLine method throws an exception, and the statement br.close() in the finally block throws an exception, then the FileReader has leaked. Therefore, use a try -with-resources statement instead of a finally block to close your program’s resources.
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.
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.
Java — попробуйте с ресурсами
Поддержка try-with-resources, представленная в Java 7, позволяет нам объявлять ресурсы, которые будут использоваться в блоке try , с гарантией того, что ресурсы будут закрыты после выполнения этого блока.
Объявленные ресурсы должны реализовать интерфейс AutoCloseable .
2. Использование попытки с ресурсами
Проще говоря, для автоматического закрытия ресурс должен быть объявлен и инициализирован внутри try :
3. Замена try – catch-finally на try- with -resources
Простой и очевидный способ использования новой функциональности try-with-resources — заменить традиционный и многословный блок try-catch-finally .
Давайте сравним следующие примеры кода.
Первый типичный блок try-catch-finally :
А вот новое супер лаконичное решение с использованием try-with-resources :
Здесь можно продолжить изучение класса Scanner .
4. попробуйте с ресурсами с несколькими ресурсами
Мы можем просто объявить несколько ресурсов в блоке try-with-resources , разделив их точкой с запятой:
5. Пользовательский ресурс с AutoCloseable
Чтобы создать пользовательский ресурс, который будет корректно обрабатываться блоком try-with-resources , класс должен реализовать интерфейсы Closeable или AutoCloseable и переопределить метод close :
6. Порядок закрытия ресурса
Ресурсы, которые были определены/получены первыми, будут закрыты последними. Давайте рассмотрим пример такого поведения:
Ресурс 1:
Ресурс 2:
Код:
Выход:
7. поймать и наконец
Блок try-with-resources может по-прежнему иметь блоки catch « и finally , которые будут работать так же, как и в традиционном блоке try .
8. Java 9 — эффективные окончательные « переменные
До Java 9 мы могли использовать свежие переменные только внутри блока try-with-resources :
Как показано выше, это было особенно многословно при объявлении нескольких ресурсов. Начиная с Java 9 и как часть JEP 213 , теперь мы можем использовать переменные final или даже эффективно final внутри блока try-with-resources :
Проще говоря, переменная фактически является final , если она не изменяется после первого присваивания, даже если она явно не помечена как final .
Как показано выше, переменная сканера явно объявлена как final , поэтому мы можем использовать ее с блоком try-with-resources . Хотя переменная записи не является явно окончательной, она не меняется после первого присваивания. Таким образом, мы также можем использовать переменную записи .
9. Заключение
В этой статье мы обсудили, как использовать try-with-resources и как заменить try , catch и, наконец , try-with-resources.
Мы также рассмотрели создание пользовательских ресурсов с помощью AutoCloseable и порядок, в котором ресурсы закрываются.
Полный исходный код примера доступен в этом проекте GitHub .
Rukovodstvo
статьи и идеи для разработчиков программного обеспечения и веб-разработчиков.
Заявление try-with-resources в Java
Введение try-with-resources — это один из нескольких операторов try в Java, призванный освободить разработчиков от обязанности освобождать ресурсы, используемые в блоке try. Первоначально он был представлен в Java 7, и вся идея заключалась в том, что разработчику не нужно беспокоиться об управлении ресурсами для ресурсов, которые они используют только в одном блоке try-catch-finally. Это достигается за счет устранения необходимости в блоках finally, которые на практике разработчики использовали только для закрытия ресурсов. Дополнительно все
Время чтения: 6 мин.
Вступление
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 и, finally часть try-with-resources работают должным образом, при этом catch обрабатывают соответствующие исключения, а finally выполняется независимо от того, было исключение или нет. Единственное отличие — это подавленные исключения, которые описаны в конце этой статьи.
Примечание . Начиная с Java 9, объявлять ресурсы в операторе try-with-resources необязательно. Вместо этого мы можем сделать что-то вроде этого:
Множественные ресурсы
Еще один хороший аспект try-with-resources — это простота добавления / удаления ресурсов, которые мы используем, с уверенностью, что они будут закрыты после того, как мы закончим.
Если бы мы хотели работать с несколькими файлами, мы открывали файлы в try() и разделяли их точкой с запятой:
Затем Java заботится о том, чтобы вызвать .close() для всех ресурсов, которые мы открыли в try() .
Примечание : они закрываются в обратном порядке объявления, что означает, что в нашем примере scanner будет закрыт раньше writer .
Поддерживаемые классы
Все ресурсы, объявленные в try() должны реализовывать интерфейс AutoCloseable Обычно это различные типы писателей, читателей, сокетов, выходных или входных потоков и т. Д. Все, что вам нужно для написания resource.close() после того, как вы закончите с ним работать.
Это, конечно, включает определяемые пользователем объекты, реализующие интерфейс AutoClosable Тем не менее, вы редко встретите ситуацию, когда вы захотите написать свои собственные ресурсы.
В случае, если это произойдет, вам необходимо реализовать AutoCloseable или Closeable (только там, чтобы сохранить обратную совместимость, предпочитайте AutoCloseable ) и переопределите метод .close() :
Обработка исключений
Если исключение выбрасывается из блока Java try-with-resources , любой ресурс, открытый в круглых скобках try все равно будет автоматически закрыт.
Как упоминалось ранее, try-with-resources работает так же, как try-catch-finally , за исключением одного небольшого дополнения. Добавление называется подавленными исключениями . Не надо понимать подавленные исключения для того , чтобы использовать примерочных с-ресурсами, но читать о них может быть полезно для отладки , когда ничего не похоже на работу.
Представьте себе ситуацию:
- По какой-то причине в блоке try-with-resources возникает исключение
- Java останавливает выполнение в блоке try-with-resources и вызывает .close() для всех ресурсов, объявленных в try()
- Один из .close() вызывает исключение
- Какое исключение « catch блок catch?
Эта ситуация знакомит нас с вышеупомянутыми подавленными исключениями. Подавленное исключение — это исключение, которое в некотором смысле игнорируется, когда оно создается в неявном блоке finally блока try-with-resources , в случае, когда исключение также генерируется из блока try
Эти исключения являются исключениями, которые возникают в .close() и доступ к ним отличается от «обычных» исключений.
Важно понимать, что порядок исполнения такой:
- блок try-with-resources
- неявный, наконец
- блок catch (если исключение было сгенерировано в [1] и / или [2])
- (явный) наконец
Например, вот ресурс, который ничего не делает, кроме исключения:
Этот код работоспособен. Вы можете использовать его, чтобы поэкспериментировать с использованием нескольких MyResource или посмотреть, что происходит, когда try-with-resources не генерирует исключение, а .close() делает.
Подсказка : внезапно стали важны исключения, возникающие при закрытии ресурсов.
Важно отметить, что если ресурс выдает исключение при попытке закрыть его, любые другие ресурсы, открытые в том же блоке try-with-resources, все равно будут закрыты.
Еще один факт, который следует отметить, заключается в том, что в ситуации, когда try не генерирует исключение и когда возникает несколько исключений при попытке использовать .close() используемые ресурсы, первое исключение будет распространяться вверх по стеку вызовов, а остальные будут подавлены.
Как вы можете видеть в коде, вы можете получить список всех подавленных исключений, Throwable массиву Throwable.getSuppressed() .
Помните, что внутри блока try может быть создано только одно исключение. Как только возникает исключение, код блока try завершается, и Java пытается закрыть ресурсы.
Заключение
По возможности следует использовать try-with-resources вместо обычного try-catch-finally . Легко забыть закрыть один из ваших ресурсов после нескольких часов написания кода или забыть закрыть ресурс, который вы только что добавили в свою программу, после случайного всплеска вдохновения.
Код более читабелен, его легче изменять и поддерживать, и, как правило, он короче.
Java Try With Resources
The Java try with resources construct, AKA Java try-with-resources, is an exception handling mechanism that can automatically close resources like a Java InputStream or a JDBC Connection when you are done with them. To do so, you must open and use the resource within a Java try-with-resources block. When the execution leaves the try-with-resources block, any resource opened within the try-with-resources block is automatically closed, regardless of whether any exceptions are thrown either from inside the try-with-resources block, or when attempting to close the resources.
This Java try-with-resources tutorial explains how the Java try-with-resources construct works, how to properly use it, and how exceptions are handled that are thrown both from inside the try-with-resources block, and during the closing of the resources.
Try-with-resources Video
I have created a video version of this Java try-with-resources tutorial, in case you prefer that:
Try-with-resources
To see how the Java try-with-resources construct work, let us look at a Java try-with-resources example:
This try-with-resources example shows how to open a Java FileInputStream inside a try-with-resources block, read some data from the FileInputStream , and have the FileInputStream closed automatically once execution leaves the try-with-resources block (not explicitly visible).
Notice the first line inside the method in the try-with-resources example above:
This is the try-with-resources construct. The FileInputStream variable is declared inside the parentheses after the try keyword. Additionally, a FileInputStream is instantiated and assigned to the variable.
When the try block finishes the FileInputStream will be closed automatically. This is possible because FileInputStream implements the Java interface java.lang.AutoCloseable . All classes implementing this interface can be used inside the try-with-resources construct.
Try-with-resources Java 9 Enhancement
Before Java 9 a resource that is to be automatically closed must be created inside the parentheses of the try block of a try-with-resources construct. From Java 9, this is no longer necessary. If the variable referencing the resource is effectively final, you can simply enter a reference to the variable inside the try block parentheses. Here is an example of the Java 9 try-with-resources enhancement:
Notice how the input variable is now declared and has a FileInputStream assigned outside the try block. Notice also, how the input variable is references inside the parentheses of the try block. This way, Java will still close it properly once the try block is exited.
Using Multiple Resources
You can use multiple resources inside a Java try-with-resources block and have them all automatically closed. Here is an example of using multiple resources inside a try-with-resources block:
This example creates two resources inside the parentheses after the try keyword. An FileInputStream and a BufferedInputStream . Both of these resources will be closed automatically when execution leaves the try block.
Closing Order
The resources declared in a Java try-with-resources construct will be closed in reverse order of the order in which they are created / listed inside the parentheses. In the example in the previous section, first the will be closed, then the FileInputStream .
Custom AutoClosable Implementations
The Java try-with-resources construct does not just work with Java’s built-in classes. You can also implement the java.lang.AutoCloseable interface in your own classes, and use them with the try-with-resources construct.
The AutoClosable interface only has a single method called close() . Here is how the interface looks:
Any class that implements this interface can be used with the Java try-with-resources construct. Here is a simple example implementation:
The doIt() method is not part of the AutoClosable interface. It is there because we want to be able to do something more than just closing the object.
Here is an example of how the MyAutoClosable is used with the try-with-resources construct:
Here is the output printed to System.out when the method myAutoClosable() is called:
As you can see, try-with-resources is a quite powerful way of making sure that resources used inside a try-catch block are closed correctly, no matter if these resources are your own creation, or Java’s built-in components.
Try-with-resources Exception Handling
The exception handling semantics of a Java try-with-resources block vary a bit from the exception handling semantics of a standard Java try-catch-finally block. In most situations the changed semantics will work better for you than the semantics of the original try-catch-finally block, even without you understanding the difference precisely. Even so, it can be a good idea to actually understand what is going on exception handling wise, in the try-with-resources construct. Therefore I will explain the exception handling semantics of the try-with-resources construct here.
If an exception is thrown from within a Java try-with-resources block, any resource opened inside the parentheses of the try block will still get closed automatically. The throwing of the exception will force the execution to leave the try block, and this will force the automatic closing of the resource. The exception thrown from inside the try block will get propagated up the call stack, once the resources have been closed.
Some resources may also throw exceptions when you try to close them. In case a resource throws an exception when you try to close it, any other resources opened within the same try-with-resources block will still get closed. After closing all resources, the exception from the failed close-attempt will get propagated up the call stack. In case multiple exceptions are thrown from multiple resource close attempts, the first exception encountered will be the one propagated up the call stack. The rest of the exceptions will be suppressed.
If an exception is thrown both from inside the try-with-resources block, and when a resource is closed (when close() is called), the exception thrown inside the try block will be propagated up the call stack. The exception thrown when the resource was attempted closed will be suppressed. This is opposite of what happens in a normal try-catch-finally block, where the last exception encountered is the exception that is propagated up the call stack.
To better understand the exception handling semantics of the Java try-with-resources construct, let us look at some examples. For these examples I have created the following AutoClosable implementation which I can force to throw exceptions both when used and when attempted closed:
First, let us look at a basic example with a single resource in use:
In case the second parameter to the AutoClosableResource construct was changed to true , it would throw an exception when attempted closed. In that case, the exception thrown when attempted closed will be propagated up the call stack to the main() method where the try-catch block will catch it. In that case, the Throwable array returned from e.getSuppessed() will be an empty array (size of 0).
In case the parameter to resourceOne.doOp() was changed to true also, the doOp() method would throw an exception. In that case, it is this exception that is propagated up the call stack to the main() method. The exception thrown when attempting to close the resource would be available inside the Throwable array returned by e.getSuppressed() .
Let us look at an example with two AutoClosable resources in use:
In the case where only one of the resources throw an exception, either during use or when attempted closed, the behaviour is the same as when only one resource is used. However, in the example above I have forced both resources to throw an exception when attempted closed, and the first resource to throw an exception when used (when doOp() is called). In that case, the exception thrown from inside the try block is propagated up the call stack. The two exceptions thrown when attempting to close the resources are available in the Throwable array returned by e.getSuppressed() .
Remember, only a single exception can be thrown inside the try block. As soon as an exception is thrown, the try block code is exited, and the resources attempted closed.
Catch Block
You can add a catch block to a try-with-resources block just like you can to a standard try block. If an exception is thrown from within the try block of a try-with-resources block, the catch block will catch it, just like it would when used with a standard try construct.
Before the catch block is entered, the try-with-resources construct will attempt to close the resources opened inside the try block. In case an exception is thrown when attempting to close one of the resources, these exceptions will be available from the exception’s getSuppressed() method inside the catch block. Here is an example of a Java try-with-resources block with a catch block attached:
In the example above, the AutoClosableResource is configured to throw an exception both when doOp() is called, and when it is attempted closed (via close() ). The exception thrown from doOp() is caught in the catch block, its getSuppressed() method returns an array with the exception thrown when the resource was attempted closed.
In case that an exception is only thrown when the resource is attempted closed, the catch block will also catch it. The getSuppressed() method of that exception will return an empty array, since no exceptions where suppressed.
Finally Block
It is also possible to add a finally block to a Java try-with-resources block. It will behave just like a standard finally block, meaning it will get executed as the last step before exiting the try-with-resources block — after any catch block has been executed.
In case you throw an exception from within the finally block of a try-with-resources construct, all previously thrown exceptions will be lost! Here is an example of throwing an exception from within the finally block of a Java try-with-resources construct:
Notice, that the exception thrown from within the catch block will be ignored because a new exception is thrown from within the finally block. This would also be true if there was no catch block. Then any exception thrown from inside the try block would get lost because a new exception is thrown from inside the finally block. Any previous exceptions are not suppressed, so they are not available from within the exception thrown from the finally block.
Adding Suppressed Exceptions Manually
The Throwable class has a method named addSuppressed() which takes a Throwable object as parameter. Using the addSuppressed() method it is possible to add suppressed exceptions to another exception, in case you need that. Here is an example that shows how to add suppressed exceptions to a Java exception manually:
Notice how the Throwable reference has to be declared outside the try-with-resources construct. Otherwise the catch and finally blocks cannot access it.
In most cases you will not need to add suppressed exceptions to an exception manually, but now you have at least seen how it can be done, in case you ever run into a situation where you need it.
Resource Management With Try-Catch-Finally, Old School Style
The Java try-with-resources construct was added in Java 7. Managing resources that need to be explicitly closed was somewhat tedious before Java 7. You had to handle the correct closure of the resources manually. This was not an easy task to handle correctly. To understand why, look at the following method which reads a file and prints it to the System.out :
The code marked in bold is where the code can throw an Exception . As you can see, that can happen in 3 places inside the try -block, and 1 place inside the finally -block.
The finally block is always executed no matter if an exception is thrown from the try block or not. That means, that the InputStream is closed no matter what happens in the try block. Or, attempted closed that is. The InputStream ‘s close() method may throw an exception too, if closing it fails.
Imagine that an exception is thrown from inside the try block. Then the finally block is executed. Imagine then, that an exception is also thrown from the finally block. Which exception do you think is propagated up the call stack?
The exception thrown from the finally block would be propagated up the call stack, even if the exception thrown from the try block would probably be more relevant to propagate.