Обработка исключений Java: try-catch-finally
В предыдущих уроках я рассмотрел блок try-catch и вложенный блок try. В этом руководстве мы увидим блок finally, который используется вместе с try-catch. Он содержит все важные операторы, которые должны быть выполнены независимо от того, происходит ли исключение.
Синтаксис
Простой пример
Здесь вы можете видеть, что исключение произошло в блоке try, который был обработан в блоке catch, после того, как этот блок finally был выполнен.
class Example < public static void main(String args[]) < try< int num=121/0; System.out.println(num); >catch(ArithmeticException e) < System.out.println("Number should not be divided by zero"); >/* Finally block will always execute * even if there is no exception in try block */ finally < System.out.println("This is finally block"); >System.out.println("Out of try-catch-finally"); > >
Number should not be divided by zero This is finally block Out of try-catch-finally
Несколько важных моментов
- Блок finally должен быть связан с блоком try, нельзя использовать его без try. Вы должны поместить в этот блок те операторы, которые должны выполняться всегда.
- Блок finally не является обязательным, как мы видели в предыдущих уроках. Try-catch достаточен для обработки исключений, однако, если вы поместите finally, он всегда будет выполняться после выполнения try.
- В нормальном случае, когда в блоке try нет исключения, тогда блок finally выполняется после блока try. Однако, если возникает, catch выполняется перед finally.
- Исключение в блоке finally работает точно так же, как и любое другое.
- Операторы, присутствующие в блоке finally, выполняются, даже если try содержит операторы передачи управления, такие как return, break или continue.
Пример с оператором return
Хотя у нас есть метод return, блок finally все равно выполняется.
class JavaFinally < public static void main(String args[]) < System.out.println(JavaFinally.myMethod()); >public static int myMethod() < try < return 112; >finally < System.out.println("This is Finally block"); System.out.println("Finally block ran even after return statement"); >> >
This is Finally block Finally block ran even after return statement 112
Случаи, когда не выполняется
Обстоятельствами, препятствующими выполнению кода в блоке finally, являются:
- окончание потока;
- использование системой метода exit();
- исключение, возникающее в блоке finally.
Оператор close()
Оператор close() используется для закрытия всех открытых потоков в программе. Хорошей практикой является использование внутри блока finally. Поскольку блок выполняется, даже если возникает исключение, вы можете быть уверены, что все входные и выходные потоки закрыты должным образом независимо от того, возникло исключение или нет.
. try < OutputStream osf = new FileOutputStream( "filename" ); OutputStream osb = new BufferedOutputStream(opf); ObjectOutput op = new ObjectOutputStream(osb); try< output.writeObject(writableObject); >finally < op.close(); >> catch(IOException e1) < System.out.println(e1); >.
Без блока catch
Блок try-finally возможен без блока catch.
. InputStream input = null; try < input = new FileInputStream("inputfile.txt"); >finally < if(input != null) < try < in.close(); >catch(IOException exp) < System.out.println(exp); >> > .
System.exit()
Оператор System.exit() ведет себя иначе, чем оператор return. Всякий раз, когда он вызывается в блоке try, finally не выполняется:
. try < //try block System.out.println("Inside try block"); System.exit(0) >catch(Exception exp) < System.out.println(exp); >finally < System.out.println("Java finally block"); >.
В приведенном выше примере, если System.exit(0) вызывается без каких-либо исключений, то, finally, не будет выполняться. Однако если при его вызове произойдет какое-либо исключение, будет выполнен блок finally.
Блок try-catch-finally
- Либо оператор try должен быть связан с блоком catch, либо с finally.
- Так как catch выполняет обработку исключений и finally выполняет очистку, лучший способ – использовать оба из них.
Примеры
Пример 1 : Демонстрируется работа блока finally, когда в блоке try не возникает исключение
class Example1 < public static void main(String args[])< try< System.out.println("First statement of try block"); int num=45/3; System.out.println(num); >catch(ArrayIndexOutOfBoundsException e) < System.out.println("ArrayIndexOutOfBoundsException"); >finally < System.out.println("finally block"); >System.out.println("Out of try-catch-finally block"); > >
First statement of try block 15 finally block Out of try-catch-finally block
Пример 2 : Показана работа блока finally, когда исключение не обрабатывается в блоке catch:
class Example2 < public static void main(String args[])< try< System.out.println("First statement of try block"); int num=45/0; System.out.println(num); >catch(ArrayIndexOutOfBoundsException e) < System.out.println("ArrayIndexOutOfBoundsException"); >finally < System.out.println("finally block"); >System.out.println("Out of try-catch-finally block"); > >
First statement of try block finally block Exception in thread "main" java.lang.ArithmeticException: / by zero at beginnersbook.com.Example2.main(Details.java:6)
Как видно, система сгенерировала сообщение об исключении, но перед этим успешно завершился блок finally.
Пример 3 : Когда исключение возникает в блоке try и обрабатывается должным образом в блоке catch:
class Example3 < public static void main(String args[])< try< System.out.println("First statement of try block"); int num=45/0; System.out.println(num); >catch(ArithmeticException e) < System.out.println("ArithmeticException"); >finally < System.out.println("finally block"); >System.out.println("Out of try-catch-finally block"); > >
First statement of try block ArithmeticException finally block Out of try-catch-finally block
The finally Block
The finally block always executes when the try block exits. This ensures that the finally block is executed even if an unexpected exception occurs. But finally is useful for more than just exception handling it allows the programmer to avoid having cleanup code accidentally bypassed by a return , continue , or break . Putting cleanup code in a finally block is always a good practice, even when no exceptions are anticipated.
Note: The finally block may not execute if the JVM exits while the try or catch code is being executed.
The try block of the writeList method that you’ve been working with here opens a PrintWriter . The program should close that stream before exiting the writeList method. This poses a somewhat complicated problem because writeList ‘s try block can exit in one of three ways.
- The new FileWriter statement fails and throws an IOException .
- The list.get(i) statement fails and throws an IndexOutOfBoundsException .
- Everything succeeds and the try block exits normally.
The runtime system always executes the statements within the finally block regardless of what happens within the try block. So it’s the perfect place to perform cleanup.
The following finally block for the writeList method cleans up and then closes the PrintWriter and FileWriter .
Important: Use a try- with-resources statement instead of a finally block when closing a file or otherwise recovering resources. The following example uses a try -with-resources statement to clean up and close the PrintWriter and FileWriter for the writeList method: