Finally java когда не работает

Вопросы по Java на собеседовании (3)

Исключение — это ошибка, возникающая во время выполнения программы. Причины возникновения исключения могут разные, например :

  • некорректно определены (не определены) данные;
  • невозможно прочитать или создать файл;
  • обрыв сетевого соединения или соединения с сервером базы данных.

Исключение в Java является объектом. Поэтому они могут не только создаваться автоматически виртуальной машиной JVM при возникновении исключительной ситуации, но и порождаться самим разработчиком.

2. Операторы исключений

Java имеет пять ключевых операторов для определения блока исключений, перехвата и возбуждения исключений :

  1. try — начала блока кода, в котором может возникнуть исключение, и которое следует перехватить;
  2. catch — начала блока кода, предназначенного для перехвата и обработки исключений (параметром catch является тип ожидаемого исключения);
  3. throw — оператор для генерации исключений;
  4. throws — ключевое слово, используемое в сигнатуре метода, и обозначающее, что метод потенциально может вызвать исключение с определенным типом;
  5. finally — начала дополнительного блока кода, размещаемый после последнего блока catch. Блок finally не является обязательным, но всегда получает управление.

Общая структура «перехвата» исключительной ситуации выглядит следующим образом :

try < // код программы, который может привести к ошибке >catch(Exception e ) < // код программы для обработки исключений >finally < // выполнение блока программы независимо от наличия исключения >

3. Оператор throws

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

public class TestThrow < static void method() throws IllegalAccessException < System.out.println("inside method"); // . . . throw new IllegalAccessException ("Exception in method"); >public static void main(String args[]) < try < method(); >catch(IllegalAccessException e) < System.out.println("Catch inside main : " + e.getMessage()); >> >

4. Блоки кода try/catch и try/finally

Каждый оператор try требует наличия либо catch, либо finally, либо сочетания catch и finally. Блок кода finally не является обязательным, и может отсутствовать при использовании try/catch. Оператором finally создаётся блок кода, который должен быть выполнен после завершения блока try/catch.

Читайте также:  Событие onload

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

Пример использования try/finally представлен здесь.

5. Может ли блок finally не выполняться?

Код блока finally не будет исполнен, если в код программы включен предшествующий блоку finally системный выход. Следующий пример демонстрирует данную ситуацию.

try < System.exit(0); >catch(Exception e) < System.err.println(e.getMessage()); >finally < // код блока >

6. Проверяемые и непроверяемые исключения

Все исключения делятся на «проверяемые» (checked) и «непроверяемые» (unchecked). Данное свойство присуще базовому классу исключения Throwable и передается по наследству (Error, Exception, RuntimeException). В исходном коде класса исключения данное свойство недоступно. Ниже представлена иерархия классов исключений.

Object | Throwable(CHECKED) / \ Error(UNCHECKED) Exception(CHECKED) | RuntimeException(UNCHECKED)

Исключения Throwable и Exception, а также все их наследники, за исключением Error и RuntimeException, являются «проверяемыми» checked исключениями. Error и RuntimeException, а также все их наследники, относятся к «непроверяемым» unchecked исключениям.

Проверка исключения на checked выполняется компилятором (compile-time checking). Непроверяемые исключения можно перехватить (catch) в момент исполнения программы (runtime checking).

Java – это язык программирования со статической типизацией, т.е. его компилятор отслеживает корректности использования типов : наличие полей и методов, checked исключения, и т.д. Следующий пример демонстрирует наличие двух ошибок программирования, определенные на этапе копиляции.

public class TestException < public static Double divide(int i1, int i2) throws Exception < if (i2 != 0) return new Double (i2 / i2); else < Throwable e = new Exception(); throw e; // Unhandled exception type Throwable >> public static void main(String[] args) < Object obj = "Hello!"; char c = obj.charAt(0); // The method charAt(int) is // undefined for the type Object >>

Сигнатура метода divide (операция деления) включает определение возможного исключения типа Exception, наследуемого от Throwable. Если делитель (i2) равен 0, то создается объект исключения типа Throwable и возбуждается исключение (throw t), которое не пропускает компилятор, т.к. тип возбуждаемого исключения не соответствует типу исключения в сигнатуре метода. Если в сигнатуре метода определить исключение типа Throwable, то ошибки не будет.

В методе main определен объект obj с инициализацией определенным значением. В следующей строке компилятор находит ошибку, связанную с отсутствием метода charAt(int) в объекте типа Object. Если выполнить приведение типа obj к String, то компилятор пропустит код : char c = ((String)ref).charAt(0).

Пример unchecked исключения представлен здесь.

7. Возбуждение исключения

Как было отмечено выше, исключение является объектом, который можно создать программно. Чтобы возбудить (выбросить) исключение используется оператор throw.

Exception e = new SQLException(); throw e;

8. Определение исключения в сигнатуре метода

В сигнатуре метода можно определить возможное проверяемое (checked) исключение. Следующий пример демонстрирует определение исключения в сигнатуре метода f1() и его перехват в конструкторе класса.

import java.io.EOFException; import java.io.FileNotFoundException; public class TestException < public TestException() < try < f1(); >catch (FileNotFoundException e) < e.printStackTrace(); >> public void f1() throws FileNotFoundException < throw new FileNotFoundException(); >public static void main(String[] args) < new TestException (); >>

9. Особенность RuntimeException

Исключение RuntimeException расширяет свойства Exception и является базовым классом для ошибок во время выполнения приложения. Данное исключение относится к необрабатываемым исключениям (unchecked). Согласно описанию класса это исключение может возникнуть во время нормальной работы JVM.

Следующий код демонстрирует пример использования непроверяемого исключения NumberFormatException (наследующего свойства RuntimeException). В функции parseInt при преобразовании строкового значения в число в режиме run-time может возникнуть исключение. Можно метод функции Integer.parseInt() «обернуть» в try/catch, а можно передать обработку исключения функции в вызывающий метод, для чего в сигнатуре определяется соответствующее исключение (throws).

public int parseInt(String s) throws NumberFormatException

10. Возбуждение исключения в методе main

Если в методе main возбудить исключение, то оно будет передано в виртуальную машину Java (JVM).

11. Множественные исключения

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

import java.io.EOFException; import java.io.FileNotFoundException; public class TestException < public void callMethods() throws EOFException, FileNotFoundException < if (f1()) f0(); >public void f0() throws EOFException < // . throw new EOFException(); >public boolean f1() throws FileNotFoundException < // . throw new FileNotFoundException(); >>

Чтобы перехватить несколько возможных исключений можно искользовать конструкцию try с несколькими catch.

try < if (f1()) f0(); >catch (FileNotFoundException e) < e.printStackTrace(); >catch (EOFException e)

12. Последовательность нескольких блоков catch

При определение нескольких блоков catch следует руководствоваться правилом обработки исключений от «младшего» к старшему. Т.е. нельзя размещать первым блоком catch (Exception e) <. >, поскольку все остальные блоки catch() уже не смогут перехватить исключение. Помните, что Exception является базовым классом, поэтому его стоит размещать последним.

Рассмотрим следующую иерархию наследования исключений :

java.lang.Object java.lang.Throwable java.lang.Exception java.io.IOException java.io.EOFException

Cамым младшим исключением является EOFException, поэтому он должен располагаться перед IOException и Exception, если используется несколько блоков catch с данными типами исключений. Следующий код является демонстрацией данного принципа.

String x = «Hello»; try < if (!x.equals("Hello")) throw new IOException(); else throw new EOFException(); >catch (EOFException e) < System.err.println("EOFException : " + e.getMessage()); >catch (IOException e) < System.err.println("IOException : " + e.getMessage()); >catch (Exception e)

13. Поглащение исключений в блоке try. finally

Если было вызвано два исключения — одно в блоке try, а второе в finally — то, при отсутствии catch, исключение в finally «проглотит» предыдущее исключение. Следует блоки с возможными исключениями всегда обрамлять операторами try/catch, чтобы не потерять важную информацию. Следующий пример демонстрирует «поглащение» исключения в блоке try новым исключением в блоке finally.

public class TestException < public TestException() < try < System.out.println(absorbingEx()); >catch (EOFException e) < System.out.println(e.getMessage()); >catch (IOException e) < System.out.println(e.getMessage()); >> public String absorbingEx() throws IOException, EOFException < try < throw new EOFException("EOFException"); // >catch (EOFException e) < // System.out.println("catch " + e.getMessage()); >finally < throw new IOException("finally IOException"); >> public static void main(String[] args) < new TestException(); System.exit(0); >>

В результате в консоль будет выведено следующее сообщение :

Чтобы не «потерять» исключение, необходимо его корректно перехватить и обработать. В примере следует убрать комментарий с блока catch.

14. Исключение SQLException

Исключение SQLException связано с ошибками при работе с базой данных. Данное исключением относится к checked исключениям, и, следовательно, проверяется на этапе компиляции.

java.lang.Object java.lang.Throwable java.lang.Exception java.sql.SQLException

Споры вокруг SQLException связаны с тем, что исключение возникает во время исполнения, а обрабатывать его приходится в коде, чтобы не ругался компилятор; может быть следовало бы отнести его к unchecked run-time исключениям? Убедительный довод разработчиков данного исключения связан с тем, что необходимо программисту обработать свои возможные ошибки при работе с базой данных.

15. Ошибка Error

Ошибка Error относится к подклассу не проверяемых (unchecked) исключений, которая показывает серьезные проблемы, возникающие во время выполнения программы. Большинство из ошибок данного класса сигнализируют о ненормальном ходе выполнения программы, т.е. о возникновении критических проблем.

Согласно спецификации Java, не следует пытаться обрабатывать Error в собственной программе, поскольку они связаны с проблемами уровня JVM. Исключения такого рода возникают, если, например, закончилась память, доступная виртуальной машине.

16. Обобщение исключений

При определении в сигнатуре метода возможных исключений можно вместо нескольких проверяемых исключений указать общее (базовое) java.lang.Throwable. В этом случае, компилятор «пропустит код» и программа возможно отработает без сбоев. Например :

public void callCommonException() throws Exception < Object obj = new Object(); method(obj); >public void method(Object obj) throws NumberFormatException, IllegalArgumentException < // . >

Использование Exception или Throwable в сигнатуре метода делает почти невозможным правильное обращение с исключениями при вызове метода. Вызывающий метод получает только информацию о том, что что-то может отработать некорректно.

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

17. Логирование исключений

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

Иногда исключение может быть частью ожидаемого поведения. В этом случае нет необходимости его регистрировать.

Источник

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