Java исключения зачем нужен finally. Исключения и их обработка. Что такое исключения

О чем и зачем эта статья?

В статье рассказывается об исключениях в языке Java, методах их обработки и некоторых особенностях работы с исключениями. Статья написана для семинара по технологиям Java, проводимого компанией i.Point .

Что такое исключения?

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

Итак, каждый раз, когда при выполнении программы происходит ошибка, то программа выбрасывает исключение - в этот момент создается специальный объект-исключение (exception-object), дальше будем называть его просто исключение. Этот объект содержит информацию о возникшей ошибке: тип ошибки, а также запись о состоянии программы на момент возникновения ошибки. Создание исключения и передача его среде выполнения называется выбрасыванием исключения (exception throwing). Посмотрим, как происходит выброс исключений при выполнении программы в Java:

Во время выполнения первого метода возникла какая-то проблема, после этого было сгенерировано исключение. В момент генерации исключения Java начинает искать для него подходящий обработчик (handler), передавая объект вверх по стеку вызовов до тех пор, пока обработчик исключения не будет найден.

Типы исключений в Java

Взглянем на иерархию классов объектов-исключений в Java:

Как мы видим, все исключения имеют общего предка - Throwable. Он имеет два важных подкласса - Exception и Error. Исключения (Exceptions) являются результатом возникших внутри программы проблем, которые в принципе решаемы и предсказуемы. Ошибки (Errors) представляют собой более серьёзные проблемы, которые, согласно спецификации Java, не следует пытаться перехватить в приложении, написанном достаточно рационально (например ошибка OutOfMemoryError происходит в тех случаях, когда JVM не хватает памяти для выполнения программы). Кроме того, у Exception есть важный потомок - RuntimeException (исключение времени выполнения). Этот класс и его потомки представляют собой исключения, которые возникают во время "нормальной работы Java-машины" (примерами таких исключений являются попытки использования нулевых ссылок на объекты, деления на ноль или выход за границы массива).

В Java все исключения делятся на три типа: контролируемые исключения(checked), ошибки (Errors) и исключения времени выполнения (RuntimeExceptions) - последние два типа также объединяют в категорию неконтролируемых (unchecked) исключений. В чем различие? Все очень просто контролируемые исключения представляют собой те ошибки, которые могут быть обработаны в ходе выполнения программы, как вы уже догадались к этому типу относятся все потомки класса Exception (но не RuntimeException). Контролируемые исключения обязательны для обработки в коде программы, они должны быть обработаны либо включением в блок try-catch, либо объявлены в сигнатуре метода.

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

Как обрабатывать исключения?

Все современные реализации языка Java придерживаются принципа обработки или объявления исключений (The Catch or Specify Requirement), который гласит, что код, который потенциально может сгенерировать контроллируемое исключение должен либо быть заключен в блок try-catch (таким образом в блоке catch мы предоставляем обработчик для исключительной ситуации), либо мы должны объявить , что наш метод может выбросить такое исключение (после ключевого слова throws, после имени метода).

Рассмотрим несколько примеров:

// Note: This class won"t compile by design! import java . io .*; import java . util . Vector ; public class ListOfNumbers { private Vector vector ; private static final int SIZE = 10 ; public ListOfNumbers () { vector = new Vector (SIZE ) ; for (int i = 0 ; i < SIZE ; i ++ ) { vector . addElement (new Integer (i )) ; } } public void writeList () { < SIZE ; i ++ ) { out . println (" Value at: " + i + " = " + vector . elementAt (i )) ; } out . close () ; } }

Этот код не скомпилируется, т.к. конструктор FileWriter требует от нас обработать IOException. Правильно написанный код должен выглядеть примерно так:

Try { //Необработанное контролируемое (checked) исключение IOException PrintWriter out = new PrintWriter (new FileWriter (" OutFile.txt " )) ; for (int i = 0 ; i < SIZE ; i ++ ) { // метод elementAt выбрасывает неконтролируемое исключение ArrayIndexOutOfBoundsException out . println (" Value at: " + i + " = " + vector . elementAt (i )) ; } catch (IOException e ){ //Пытаемся как-то исправить ситуацию, если ошибка возникла при создании файла OutFile.txt } catch (Exception e ){ //В случае если в блоке try будет сгенерировано не IOException, то управление перейдет сюда } finally { //В любом случае нам необходимо закрыть файл. if (out != null ){ out . close () ; } }

Таким образом мы обрабатываем исключение IOException. Обратите внимание на порядок объявления блоков catch - если поменять их местами, то код не скомпилируется, т.к. IOException подкласс Exception, то код обработки IOException станет недостижимым и компилятор выдаст ошибку. Особого внимания заслуживает блок finally - код в этом блоке выполняется всегда, независимо от того, что произошло в блоках try и catch.

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

Public void writeList () throws IOException { //теперь нам не нужно самим обрабатывать исключение. }

Обрабатывать или объявлять?

Когда нам следует обрабатывать исключения, а когда объявлять? Очень простой вопрос.. жаль что на него нет однозначного ответа. В целом, следует придерживаться следующего правила:

Обрабатывайте исключение, когда вы можете это сделать; объявляйте исключение, когда вы вынуждены так поступить.

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

Преимущества, которые дает нам использование исключений

написать тут про errorcodes и раскрыть списочег

  1. Разделение обычного кода и кода обработки ошибок
  2. Возможность передачи исключений для обработки вверх по стеку вызовов
  3. Группировка и обработка ошибок по типам

Проблемы, связанные с обработкой исключений

"Потерянные исключения"

Вообще, исключения в Java очень удобны и просты, но, к сожалению, и у них есть недостаток. Хотя исключения являются индикаторами проблем в программе и не должны игнорироваться, возможна ситуация, при которой исключение просто потеряется. Это может произойти, если мы неправильно напишем код в блоке finally. Рассмотрим простой пример:

// Как может быть потеряно исключение. class VeryImportantException extends Exception { public String toString () { return " A very important exception! " ; } } class HoHumException extends Exception { public String toString () { return " A trivial exception " ; } } public class LostMessage { void f () throws VeryImportantException { throw new VeryImportantException () ; } void dispose () throws HoHumException { throw new HoHumException () ; } public static void main (String args ) throws Exception { LostMessage lm = new LostMessage () ; try { lm . f () ; } finally { lm . dispose () ; } } }

Что же мы получим в результате выполнения этого кода?

Exception in thread "main" A trivial exception
at LostMessage.dispose(LostMessage.java:21)
at LostMessage.main(LostMessage.java:29)

О ужас, мы потеряли очень важное для нас VeryImportantException, получив вместо него менее значительное.
Поэтому при написании кода в блоке finally нужно быть очень осторожными, чтобы не происходило подобных потерь информации.

Привет, Хабр! Представляю вашему вниманию перевод статьи Fixing 7 Common Java Exception Handling Mistakes автора Thorben Janssen.

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

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

Ошибка 1: объявление java.lang.Exception или java.lang.Throwable

Как вы уже знаете, вам нужно либо объявить, либо обработать проверяемое исключение. Но проверяемые исключения - это не единственные, которые вы можете указать. Вы можете использовать любой подкласс java.lang.Throwable в предложении throws. Таким образом, вместо указания двух разных исключений, которые выбрасывает следующий фрагмент кода, вы можете просто использовать исключение java.lang.Exception в предложении throws.

Public void doNotSpecifyException() throws Exception { doSomething(); } public void doSomething() throws NumberFormatException, IllegalArgumentException { // do something }
Но это не значит, что вы должны это сделать. Указание Exeption или Throwable делает почти невозможным правильное обращение с ними при вызове вашего метода.Единственная информация, которую получает вызывающий вами метод, заключается в том, что что-то может пойти не так. Но вы не делитесь какой-либо информацией о каких-либо исключительных событиях, которые могут произойти. Вы скрываете эту информацию за обобщенными причинами выброса исключений.Становится еще хуже, когда ваше приложение меняется со временем. Выброс обобщенных исключений скрывает все изменения исключений, которые вызывающий должен ожидать и обрабатывать. Это может привести к нескольким непредвиденным ошибкам, которые необходимо найти в тестовом примере вместо ошибки компилятора.

Используйте конкретные классы

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

Public void specifySpecificExceptions() throws NumberFormatException, IllegalArgumentException { doSomething(); }

Ошибка 2: перехват обобщенных исключений

Серьезность этой ошибки зависит от того, какой программный компонент вы реализуете, и где вы обнаруживаете исключение. Возможно, было бы хорошо поймать java.lang.Exception в основном методе вашего приложения Java SE. Но вы должны предпочесть поймать определенные исключения, если вы реализуете библиотеку или работаете над более глубокими слоями вашего приложения.

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

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

Try { doSomething(); } catch (NumberFormatException e) { // handle the NumberFormatException log.error(e); } catch (IllegalArgumentException e) { // handle the IllegalArgumentException log.error(e); }

Ошибка 3: Логирование и проброс исключений

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

1. У вас недостаточно информации о прецеденте, который хочет реализовать вызывающий объект вашего метода. Исключение может быть частью ожидаемого поведения и обрабатываться клиентом. В этом случае нет необходимости регистрировать его. Это добавит ложное сообщение об ошибке в файл журнала, который должен быть отфильтрован вашей операционной группой.

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

3. Вы можете регистрировать одно и то же исключение несколько раз, когда вы регистрируете его в каждом блоке catch, который его ловит. Это испортит статистику в вашем инструменте мониторинга и затрудняет чтение файла журнала для ваших операций и команды разработчиков.

Регистрируйте исключение там, где вы его обрабатываете

Таким образом, лучше всего регистрировать исключение тогда, когда вы его обрабатываете. Как в следующем фрагменте кода. Метод doSomething генерирует исключение. Метод doMore просто указывает его, потому что у разработчика недостаточно информации для его обработки. Затем он обрабатывается в методе doEvenMore, который также записывает сообщение журнала.

Public void doEvenMore() { try { doMore(); } catch (NumberFormatException e) { // handle the NumberFormatException } catch (IllegalArgumentException e) { // handle the IllegalArgumentException } } public void doMore() throws NumberFormatException, IllegalArgumentException { doSomething(); } public void doSomething() throws NumberFormatException, IllegalArgumentException { // do something }

Ошибка 4: использование исключений для управления потоком

Использование исключений для управления потоком вашего приложения считается анти-шаблоном по двум основным причинам:

Они в основном работают как оператор Go To, потому что они отменяют выполнение блока кода и переходят к первому блоку catch, который обрабатывает исключение. Это делает код очень трудным для чтения.

Они не так эффективны, как общие структуры управления Java. Как видно из названия, вы должны использовать их только для исключительных событий, а JVM не оптимизирует их так же, как и другой код.Таким образом, лучше использовать правильные условия, чтобы разбить свои циклы или инструкции if-else, чтобы решить, какие блоки кода должны быть выполнены.

Ошибка 5: удалить причину возникновения исключения

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

Когда вы создаете новое исключение, вы всегда должны устанавливать первоначальное исключение в качестве причины. В противном случае вы потеряете трассировку сообщения и стека, которые описывают исключительное событие, вызвавшее ваше исключение. Класс Exception и все его подклассы предоставляют несколько методов-конструкторов, которые принимают исходное исключение в качестве параметра и задают его как причину.

Ошибка 6: Обобщение исключений

Когда вы обобщаете исключение, вы ловите конкретный, например, NumberFormatException, и вместо этого генерируете неспецифическое java.lang.Exception. Это похоже, но даже хуже, чем первая ошибка, которую я описал в этой статье. Он не только скрывает информацию о конкретном случае ошибки на вашем API, но также затрудняет доступ.

Public void doNotGeneralizeException() throws Exception { try { doSomething(); } catch (NumberFormatException e) { throw new Exception(e); } catch (IllegalArgumentException e) { throw new Exception(e); } }
Как вы можете видеть в следующем фрагменте кода, даже если вы знаете, какие исключения может вызвать метод, вы не можете просто их поймать. Вам нужно поймать общий класс Exception и затем проверить тип его причины. Этот код не только громоздкий для реализации, но его также трудно читать. Становится еще хуже, если вы сочетаете этот подход с ошибкой 5. Это удаляет всю информацию об исключительном событии.

Try { doNotGeneralizeException(); } catch (Exception e) { if (e.getCause() instanceof NumberFormatException) { log.error("NumberFormatException: " + e); } else if (e.getCause() instanceof IllegalArgumentException) { log.error("IllegalArgumentException: " + e); } else { log.error("Unexpected exception: " + e); } }
Итак, какой подход лучший?

Будьте конкретны и сохраняйте причину возникновения исключения.

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

Try { doSomething(); } catch (NumberFormatException e) { throw new MyBusinessException(e, ErrorCode.CONFIGURATION_ERROR); } catch (IllegalArgumentException e) { throw new MyBusinessException(e, ErrorCode.UNEXPECTED); }

Ошибка 7: добавление ненужных преобразований исключений

Как я уже объяснял ранее, может быть полезно обернуть исключения в пользовательские, если вы установите исходное исключение в качестве причины. Но некоторые архитекторы переусердствуют и вводят специальный класс исключений для каждого архитектурного уровня. Таким образом, они улавливают исключение в уровне персистентности и переносят его в MyPersistenceException. Бизнес-уровень ловит и обертывает его в MyBusinessException, и это продолжается до тех пор, пока оно не достигнет уровня API или не будет обработано.

Public void persistCustomer(Customer c) throws MyPersistenceException { // persist a Customer } public void manageCustomer(Customer c) throws MyBusinessException { // manage a Customer try { persistCustomer(c); } catch (MyPersistenceException e) { throw new MyBusinessException(e, e.getCode()); } } public void createCustomer(Customer c) throws MyApiException { // create a Customer try { manageCustomer(c); } catch (MyBusinessException e) { throw new MyApiException(e, e.getCode()); } }
Легко видеть, что эти дополнительные классы исключений не дают никаких преимуществ. Они просто вводят дополнительные слои, которые оборачивают исключение. И хотя было бы забавно обернуть подарок во множестве красочной бумаги, это не очень хороший подход к разработке программного обеспечения.

Обязательно добавьте информацию

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

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

Public void persistCustomer(Customer c) { // persist a Customer } public void manageCustomer(Customer c) throws MyBusinessException { // manage a Customer throw new MyBusinessException(e, e.getCode()); } public void createCustomer(Customer c) throws MyBusinessException { // create a Customer manageCustomer(c); }


2. Какова иерархия исключений.
3. Можно/нужно ли обрабатывать ошибки jvm?
4. Какие существуют способы обработки исключений?
5. О чем говорит ключевое слово throws?
6. В чем особенность блока finally? Всегда ли он исполняется?
7. Может ли не быть ни одного блока catch при отлавливании исключений?
8. Могли бы вы придумать ситуацию, когда блок finally не будет выполнен?
9. Может ли один блок catch отлавливать несколько исключений (с одной и разных веток наследований)?
10. Что вы знаете об обрабатываемых и не обрабатываемых (checked/unchecked) исключениях?
11. В чем особенность RuntimeException?
12. Как написать собственное (“пользовательское”) исключение? Какими мотивами вы будете руководствоваться при выборе типа исключения: checked/unchecked?
13. Какой оператор позволяет принудительно выбросить исключение?
14. Есть ли дополнительные условия к методу, который потенциально может выбросить исключение?
15. Может ли метод main выбросить исключение во вне и если да, то где будет происходить обработка данного исключения?
16. Если оператор return содержится и в блоке catch и в finally, какой из них “главнее”?
17. Что вы знаете о OutOfMemoryError?
18. Что вы знаете о SQLException? К какому типу checked или unchecked оно относится, почему?
19. Что такое Error? В каком случае используется Error. Приведите пример Error’а.
20. Какая конструкция используется в Java для обработки исключений?
21. Предположим, есть блок try-finally. В блоке try возникло исключение и выполнение переместилось в блок finally. В блоке finally тоже возникло исключение. Какое из двух исключений “выпадет” из блока try-finally? Что случится со вторым исключением?
22. Предположим, есть метод, который может выбросить IOException и FileNotFoundException в какой последовательности должны идти блоки catch? Сколько блоков catch будет выполнено?

Ответы

1. Дайте определение понятию “исключение”

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

  1. Пользователь ввел некорректные данные.
  2. Файл, к которому обращается программа, не найден.
  3. Сетевое соединение с сервером было утеряно во время передачи данных. И т.д.

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

2. Какова иерархия исключений.

Исключения делятся на несколько классов, но все они имеют общего предка - класс Throwable. Его потомками являются подклассы Exception и Error.

Исключения (Exceptions) являются результатом проблем в программе, которые в принципе решаемые и предсказуемые. Например, произошло деление на ноль в целых числах.

Ошибки (Errors) представляют собой более серьёзные проблемы, которые, согласно спецификации Java, не следует пытаться обрабатывать в собственной программе, поскольку они связаны с проблемами уровня JVM. Например, исключения такого рода возникают, если закончилась память, доступная виртуальной машине. Программа дополнительную память всё равно не сможет обеспечить для JVM.

В Java все исключения делятся на два типа: контролируемые исключения (checked) и неконтролируемые исключения (unchecked), к которым относятся ошибки (Errors) и исключения времени выполнения (RuntimeExceptions, потомок класса Exception).

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

3. Можно/нужно ли обрабатывать ошибки jvm?

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

4. Какие существуют способы обработки исключений?

В Java есть пять ключевых слов для работы с исключениями:

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

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

Подробнее http://www.quizful.net/post/java-exceptions

5. О чем говорит ключевое слово throws?

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

6. В чем особенность блока finally? Всегда ли он исполняется?

Когда исключение передано, выполнение метода направляется по нелинейному пути. Это может стать источником проблем. Например, при входе метод открывает файл и закрывает при выходе. Чтобы закрытие файла не было пропущено из-за обработки исключения, был предложен механизм finally .

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

7. Может ли не быть ни одного блока catch при отлавливании исключений?

Такая запись допустима, если имеется связка try{} finally {}. Но смысла в такой записи не так много, всё же лучше иметь блок catch в котором будет обрабатываться необходимое исключение.

String x = "z"; try { x="234"; } finally { x = "Finally"; }

String x = "z" ;

try {

x = "234" ;

} finally {

x = "Finally" ;

8. Могли бы вы придумать ситуацию, когда блок finally не будет выполнен?

Блок finally выполняется не всегда, например в такой ситуации:

try { System.exit(0); } catch(Exception e) { e.printStackTrace(); } finally { }

try {

System . exit (0 ) ;

} catch (Exception e ) {

e . printStackTrace () ;

} finally { }

Здесь finally недостижим, так как происходит системный выход из программы. Общими словами: когда jvm умирает, ей не до finally (отсюда можете придумать другие примеры как убить jvm и ответить на вопрос в заголовке).

9. Может ли один блок catch отлавливать несколько исключений (с одной и разных веток наследований)?

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

try { ... } catch(IOException | SQLException ex) { logger.log(ex); throw ex; }

try {

. . .

} catch (IOException | SQLException ex ) {

logger . log (ex ) ;

throw ex ;

10. Что вы знаете об обрабатываемых и не обрабатываемых (checked/unchecked) исключениях?

Все исключительные ситуации делятся на «проверяемые» (checked) и «непроверяемые» (unchecked) (смотрите картинку в начале статьи). Это свойство присуще «корневищу» (Throwable, Error, Exception, RuntimeException) и передается по наследству. Никак не видимо в исходном коде класса исключения.
В дальнейших примерах просто учтите, что- Throwable и Exception и все их наследники (за исключением наследников Error-а и RuntimeException-а) - checked
- Error и RuntimeException и все их наследники - unchecked
checked exception = проверяемое исключение, проверяемое компилятором.

Тема достаточно обширная для того, чтобы уместить ее в одном ответе. К примеру, можно разобрать примеры Головача: http://habrahabr.ru/company/golovachcourses/blog/225585/

И еще с quizful.net

1. Checked исключения, это те, которые должны обрабатываться блоком catch или описываться в сигнатуре метода. Unchecked могут не обрабатываться и не быть описанными.
2. Unchecked исключения в Java — наследованные от RuntimeException, checked — от Exception (не включая unchecked).

Checked исключения отличаются от Unchecked исключения в Java, тем что:
1)Наличие\обработка Checked исключения проверяются на этапе компиляции . Наличие\обработка Unchecked исключения происходит на этапе выполнения .

11. В чем особенность RuntimeException?

public class RuntimeException extends Exception — базовый класс для ошибок во время выполнения. Относится к необрабатываемым исключениям (uncatched\unchecked). Как сказано в описании класса — это суперкласс, исключения которого могут быть выброшены во время нормальной работы JVM.

12. Как написать собственное (“пользовательское”) исключение? Какими мотивами вы будете руководствоваться при выборе типа исключения: checked/unchecked?

Необходимо унаследоваться от базового класса требуемого типа исключений (например от Exception или RuntimeException).

public class ExcClass extends Exception { private String someString; public ExcClass (String string) { this.someString = string; System.out.println("Exception ExcClass"); } public void myOwnExceptionMsg() { System.err.println("This is exception massage for string: " + someString); } } public class TestExc { public static void main(String args) { try { String s = "SomeString"; throw new ExcClass(s); } catch (ExcClass ex) { ex.myOwnExceptionMsg(); } } } //Вывод Exception ExcClass This is exception massage for string: SomeString

public class ExcClass extends Exception {

private String someString ;

public ExcClass (String string ) {

this . someString = string ;

System . out . println ("Exception ExcClass" ) ;

public void myOwnExceptionMsg () {

System . err . println ("This is exception massage for string: " + someString ) ;

public class TestExc {

try {

String s = "SomeString" ;

throw new ExcClass (s ) ;

} catch (ExcClass ex ) {

ex . myOwnExceptionMsg () ;

//Вывод

Exception ExcClass

This is exception massage for string : SomeString

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

13. Какой оператор позволяет принудительно выбросить исключение?

throw new Exception();

14. Есть ли дополнительные условия к методу, который потенциально может выбросить исключение?

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

Public void someMethod() throws Exception { }

public void someMethod () throws Exception {

15. Может ли метод main выбросить исключение во вне и если да, то где будет происходить обработка данного исключения?

Может и оно будет передано в виртуальную машину Java (JVM).

16. Если оператор return содержится и в блоке catch и в finally, какой из них “главнее”?

Вернется из блока finally.

Public static void main(String args) { String what = method(); System.out.println(what); } public static String method() { try { return "SomeString"; } finally { return "Finally message"; } } //Вывод Finally message

public static void main (String args ) {

String what = method () ;

System . out . println (what ) ;

public static String method () {

try {

return "SomeString" ;

} finally {

return "Finally message" ;

//Вывод

Finally message

17. Что вы знаете о OutOfMemoryError?

OutOfMemoryError выбрасывается, когда виртуальная машина Java не может выделить (разместить) объект из-за нехватки памяти, а сборщик мусора не может высвободить ещё.

Область памяти, занимаемая java процессом, состоит из нескольких частей. Тип OutOfMemoryError зависит от того, в какой из них не хватило места.

1. java.lang.OutOfMemoryError: Java heap space
Не хватает места в куче, а именно, в области памяти в которую помещаются объекты, создаваемые программно в вашем приложении. Размер задается параметрами -Xms и -Xmx. Если вы пытаетесь создать объект, а места в куче не осталось, то получаете эту ошибку. Обычно проблема кроется в утечке памяти, коих бывает великое множество, и интернет просто пестрит статьями на эту тему.

2. java.lang.OutOfMemoryError: PermGen space
Данная ошибка возникает при нехватке места в Permanent области, размер которой задается параметрами -XX:PermSize и -XX:MaxPermSize.

3. java.lang.OutOfMemoryError: GC overhead limit exceeded
Данная ошибка может возникнуть как при переполнении первой, так и второй областей. Связана она с тем, что памяти осталось мало и GC постоянно работает, пытаясь высвободить немного места. Данную ошибку можно отключить с помощью параметра -XX:-UseGCOverheadLimit, но, конечно же, её надо не отключать, а либо решать проблему утечки памяти, либо выделять больше объема, либо менять настройки GC.

4. java.lang.OutOfMemoryError: unable to create new native thread

Выбрасывается, когда нет возможности создать еще потоки.

Подробнее в статье http://habrahabr.ru/post/117274/

18. Что вы знаете о SQLException? К какому типу checked или unchecked оно относится, почему?

SQLException предоставляет информацию об ошибках доступа к базе данных или других ошибках связанных с работой с базами данных.

SQLException относится к checked исключениям, а значит проверяется на этапе компиляции.

Споры об этом типе исключения идут о том, что разработчику приходится постоянно обрабатывать это исключение в коде, хотя большая часть ошибок возникает во время выполнения программы, т.е., по мнению многих, лучше бы отнести его к unchecked runtime исключениям.

try { // make some SQL call(s) } catch {SQLException e) { // log the exception return; // and give up }

try {

// make some SQL call(s)

} catch { SQLException e ) {

// log the exception

return ; // and give up

Аргумент Joshua Bloch из Effective Java Second Edition такой: сделав SQLException проверяемым — это попытка заставить разработчиков обработать исключение и обернуть его в новом уровне абстракции.

19. Что такое Error? В каком случае используется Error. Приведите пример Error’а.

Ошибки (Errors) представляют собой более серьёзные проблемы, которые, согласно спецификации Java, не следует пытаться обрабатывать в собственной программе, поскольку они связаны с проблемами уровня JVM. Например, исключения такого рода возникают, если закончилась память, доступная виртуальной машине.

За примером посмотрите картинку иерархии исключений вначале статьи. Как пример — OutOfMemoryError.

20. Какая конструкция используется в Java для обработки исключений?

Можно использовать try-catch-finally и c 7й Java try-with-resources. Первый способ:

try{ //здесь код, который потенциально может привести к ошибке } catch(SomeException e){ //в скобках указывается класс конкретной ожидаемой ошибки //здесь описываются действия, направленные на обработку исключений } finally{ //выполняется в любом случае (блок finally не обязателен) }

Try с ресурсами:

Старый способ BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { if (br != null) { br.close(); } } JDK 7 try (BufferedReader br = new BufferedReader(new FileReader(path))) { return br.readLine(); }

Старыйспособ

BufferedReader br = new BufferedReader (new FileReader (path ) ) ;

try {

return br . readLine () ;

} finally {

if (br != null ) {

br . close () ;

JDK 7

try (BufferedReader br =

new BufferedReader (new FileReader (path ) ) ) {

return br . readLine () ;

Так же смотрите ответ к «Какие существуют способы обработки исключений?»

21. Предположим, есть блок try-finally. В блоке try возникло исключение и выполнение переместилось в блок finally. В блоке finally тоже возникло исключение. Какое из двух исключений “выпадет” из блока try-finally? Что случится со вторым исключением?

Ответ аналогичный случаю с двумя return — будет обработано в finally блоке. Если было выброшено два исключения — одно в try, второе в finally, то исключение в finally «проглотит» исключение выше (см. пример). Если до блока finally исключение было обработано, то мы можем получить информацию об исключении в блоке try и тем самым не потерять исключение, которое впоследствии может быть перезаписано в finally другим исключением.

public class TestExc { public static void main(String args) { Exception ex = twoExceptionsMethod(); System.out.println(ex.getClass()); String s = twoExceptionsMethod2(); System.out.println(s); } public static Exception twoExceptionsMethod() { try { return new IndexOutOfBoundsException(); } finally { return new NullPointerException(); } } public static String twoExceptionsMethod2() { try { throw new NullPointerException(); }catch (NullPointerException ex) { System.out.println(ex.getMessage()+ " catchBlock");; } finally { Exception ex2 = new Exception(); return ex2.getMessage() + "finallyBlock"; } } } //Вывод class java.lang.NullPointerException null catchBlock null finallyBlock

public class TestExc {

public static void main (String args ) {

Exception ex = twoExceptionsMethod () ;

System . out . println (ex . getClass () ) ;

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

Когда может понадобиться обработка исключений

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

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

Что необходимо учитывать? Язык Java обладает своим встроенным функционалом обработки исключений. Конечно же большой процент ошибок отлавливается ещё на стадии компиляции, когда система автоматически сообщит о том, что использовать её дальше невозможно. Но существует и такой вид исключений, который возникает во время работы программы. Разработчик должен суметь предвидеть это и спроектировать код таким образом, чтобы он не вызвал ошибки, а обработал её особым способом или передал управление в другую ветку.

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

Типичные исключения

Самым простым примером, при котором можно получить исключение — это деление. Несмотря на всю его простоту, в выражении, в качестве делителя, может оказаться ноль, что приведёт к ошибке. Хорошо, если его появление можно предсказать ранее и предотвратить. Но такой вариант доступен не всегда, поэтому отлов исключения нужно организовать непосредственно при возникновении «деления на ноль».

В Java механизм обработки перехвата ошибки выглядит так:

  • в куче создаётся объект исключения, так же как и любой другой;
  • естественный ход программы прерывается;
  • механизм исключения пытается найти альтернативный способ продолжения кода;
  • найдя место безопасного исполнения программы в обработчике, работа либо восстановится, либо произойдёт реализация исключения особым способом.

Простейший пример создания ошибки может выглядеть таким образом:

throw new NullPointerException();

Здесь переменная a проверяется на инициализацию, т.е. не равна ли ссылка на объект null. В случае, если такая ситуация возникла и нужна особая обработка, выбрасывается исключение с помощью throw new NullPointerException().

Немного подробностей о ключевых словах

При работе с исключениями часто приходится использовать ключевые слова Java для обозначения того или иного действия. В данном языке программирования их пять:

  • Try. уже встречалось и означает оно переход в участок кода, который может сгенерировать исключение. Блок ограничивается фигурными скобками {}.
  • Catch. Перехватывает нужный тип исключения и обрабатывает его соответствующим образом.
  • Finally. Данное ключевое слово является дополнительным и служит для выполнения некоего участка кода, который необходим в любом случае, даже если ни одно исключение не перехвачено. Добавляется непосредственно после блока try.
  • Throw — позволяет создавать исключения Java в любом месте кода.
  • Throws — ключевое слово, которое ставится в сигнатуре метода. Оно означает, что последующий код может выбросить исключение Java указанного типа. Такая метка служит сигналом для разработчиков, что нужно иметь в виду — метод может сработать не так, как от него ожидают.

Отлов с помощью try

Выброс в Java исключения, естественно предполагает, что оно будет особым образом обработано. Удобнее всего это сделать, если участок кода отгорожен в некий блок. Который возможно содержит исключение. При выполнении такого кода виртуальная машина найдёт непредвиденную ситуацию, поймёт, что находится в критическом блоке и передаст управление в участок с обработкой.

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

Самый типичный код с блоком обработки выглядит так:

//Здесь будет определён код, который может породить исключение

} catch (Тип_исключения_1 идентификатор_1) {

} catch (Тип_исключения_2 идентификатор_2) {

//Здесь происходит обработка исключения, согласно его типу и условиям;

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

Finally

Как стало понятно из предыдущей главы, блоки catch ловят исключения и обрабатывают их. Но очень часто возникает ситуация, когда должен выполниться некий код вне зависимости от того, были ли отловлены ошибки. Для этого существует ключевое слово finally. Оно применяется для увеличения значений различных счётчиков, закрытия файлов или соединений с сетью.

В данном участке представлены несколько блоков catch с придуманными методами отлова исключений. К примеру, код, содержащийся в try порождает непредвиденную ситуацию типа Cold. Тогда в консоль будут выведены выражения «Caught cold!» и «Is that something to cheer about?». То есть блок finally выполняется в любом случае.

На самом деле способ избежать запуска finally существует. Связан он с завершением работы виртуальной машины. Найти, как это реализовать, можно на просторах сети Интернет.

Ключевое слово throw

Throw генерирует исключение. Его синтаксис выглядит так:

throw new NewException();

Здесь создаётся новое исключение с типом NewException(). В качестве типа могут использоваться уже входящие в стандартные библиотеки Java классы и определённые ранее разработчиком собственного производства.

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

Ключевое слово throws

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

Эта метка является своеобразным указателем для клиентских разработчиков о том, что метод не способен обработать своё же исключение. К тому же, если тип ошибки является проверяемым, то компилятор заставит явно это указать.

Try с ресурсами

В Java версии 7 разработчики включили такое важное нововведение, как обработка блока try с ресурсами.

Многие создаваемые объекты в Java, после их использования должны быть закрыты для экономии ресурсов. Раньше приходилось это учитывать и останавливать такие экземпляры вручную. Теперь же в них появился интерфейс AutoClosable. Он помогает автоматически закрывать уже использованные объекты, помещённые в блок try. Благодаря такому подходу писать код стало удобней, в его читаемость значительно повысилась.

Собственные классы исключений Java

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

Простейший способ создания — унаследовать от наиболее подходящего к контексту объекта.

Здесь произошло наследование от Exception, класса, который используется для определения собственных исключений. В MyException имеются два конструктора — один по умолчанию, второй — с аргументом msg типа String.

Затем в public классе FullConstructors реализован метод f, сигнатура которого содержит throws MyException. Это ключевое слово означает, что f может выбросить исключение Java типа MyException. Далее в теле метода производится вывод текстовой информации в консоль и собственно сама генерация MyException, посредством throw.

Второй метод немного отличается от первого тем, что при создании исключения, ему передается строковый параметр, который будет отражён в консоли при отлове. В main видно, что f() и g() помещены в блок проверки try, а ключевое слово catch настроено на отлов MyException. Результатом обработки будет вывод сообщения об ошибке в консоль:

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

Архитектура исключений

Как и все объекты в Java, исключения также наследуются и имеют иерархическую структуру. Корневым элементом всех ошибок, выбрасываемых в этом языке программирования является класс java.lang.Throwable. От него наследуются два вида — Error и Exception.

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

Наиболее часто используемым классом для создания и анализа исключений служит Exception. Который, в свою очередь, делится на несколько веток, в том числе RuntimeException. К RuntimeException относятся исключения времени выполнения, то есть происходящие во время работы программы. Все унаследованные от него классы являются непроверяемыми.

Часто встречаемые исключения

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

  • ArithmeticException. Сюда входят ошибки связанные с арифметическими операциями. Самый яркий пример — деление на ноль.
  • ArrayIndexOutOfBoundsException — обращение к номеру элемента массива, который превышает общую его длину.
  • ArrayStoreException — попытка присвоить элементу массива несовместимого типа.
  • ClassCastException — попытка неправильного приведения одного типа к другому.
  • IllegalArgumentException — использование неправильного аргумента в вызове метода.
  • NegativeArraySizeException — исключение при создании массива отрицательного размера.
  • NullPointerException — неправильное использование ссылки на null.
  • NumberFormatException — возникает при неверном преобразовании строки в число.
  • UnsupportedOperationException — операция не поддерживается.

Данные примеры представляют собой непроверяемые типы исключений Java. А вот так выглядят проверяемые:

  • ClassNotFoundException — класс не обнаружен.
  • IllegalAcccessException — ограничение доступа к классу.
  • InterruptedException — прерывание работы потока.
  • NoSuchFieldException — не существует требуемое поле.

Интерпретация исключений

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

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

ArrayIndexOutOfBoundsException. Любая программа не может существовать без использования массивов. Соответственно, частое обращение к ним может порождать и ошибки. Возникает исключение, когда разработчик пытается обратиться к элементу массива, который отсутствует в списке индексов. Например, запрашиваемое значение выше длины или меньше нуля. Очень часто появляется в результате того, что счёт в массиве начинается с нуля.

Выводы

Обработка исключений Java — мощный инструмент среды, который значительно облегчает работу программиста и позволяет ему создавать чистый и лишенный ошибок код. От того, насколько плавно и стабильно функционирует приложение, зависит статус и репутация компании-разработчика.

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

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

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

Блок try, блок catch

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

Обработчики исключений объявляются в блоке catch, который следует сразу за блоком try.

Блоков catch может быть несколько для одного блока try.

В блоке catch идёт обработка исключений, а его аргумент указывает тип исключения, который может обработать данный блок, т.е. тип аргумента есть тип исключения. Код, записанный в блоке catch есть обработчик исключения.

Блок finally

После блока(ов) ислючения может располагаться блок finally. Приемлем случай, когда нет блоков catch, но есть блок finally. Код блока finally выполняется всегда, а не только при возникновении исключения. В нем можно выполнять обязательные завершающие действия, очистку, например, закрыть поток, а не в блоке try. После finally выполнение программы продолжается со следующей строки кода.

Схематично всё выглядет так:

Public void aFunc() { try { //код } catch(TypeException e) { //код обработчика исключения типа //TypeException; } catch(SecondTypeException e) { //код обработчика исключения типа //SecondTypeException; } finally { //обязательные завершающие действия. //Код блока finally //выполняется всегда, а не только при //возникновении исключения. } }

а может быть без блоков catch, вот так:

Public void aFunc() { try { //код } finally { //обязательные завершающие действия. //Код блока finally //выполняется всегда, а не только при //возникновении исключения. } }

или без блока finally:

Public void aFunc() { try { //код } catch(TypeException e) { //код обработчика исключения типа //TypeException; } }

Рассмотрим подробнее, что происходит при возникновении исключительной ситуации.

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

Врезка

Стек вызовов(call stack)

Стек вызовов(call stack) – это пследовательность вызовов методов, начиная от метода main до интересующего нас метода. Рассмотрим условный пример. Есть класс:

Public class AClass { public AClass() {} public void methodC() { } public void methodB() { methodC(); } public void methodA() { try { methodB(); } catch(AnException e) { System.out.println(e.getMessage()); } } public static void main(String args) { AClass ac = new Aclass(); ac.methodA(); } }

Здесь стек вызовов такой: main вызывает methodA(), methodA() вызывает methodB(), methodB() вызывает methodС().

Конец врезки

Продолжим изучение действий системы после получения ею объекта исключения (предположим, что тип объекта исключения - AnException), выброшенного каким-то методом. Пусть это будет метод methodС(), см. врезку «Стек вызовов » выше. Система начинает просматривать стек вызовов для methodС() в обратном порядке, т.е, стартуя с самого метода methodС(), перемещается в напралении main. Цель этого просмотра – найти обработчик исключения, возникшего в methodС(). Сначала система просматривает methodС(), если в нём нет нужного обработчика исключения, то переходит к methodB(), если и в нём нет, то переходит к methodA(). methodA() содержит обработчик типа AnException, вот этому-то обработчику и передаёт система объект исключения на обработку. Говорят, что обработчик захватывает (catch) исключение. Если система не нашла бы обработчик ислючения нужного типа, то выполнение программы было бы завершено.

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

Три категории исключений

Контролируемые (checked) исключения . Например, ошибки ввода. Такие исключения рекомендуется обрабатывать;

Ошибка (error) . Это исключения, вызванные внешними, по отношению к приложению, причинами и приложение их, как правило, не обрабатывает. Такие исключения определяются классом Error или его подклассами;

Исключения времени выполнения (runtime exception) . Например, ошибки в коде. Такие исключения определяются классом RuntimeException или его подклассами. Эти исключения могут обрабатываться.

Исключения второго и третьего типа называют неконтролируемые (unchecked) исключения .

Метод может не обрабатывать исключение, но, предполагая, что оно может возникнуть, передать его на обработку в стек вызовов. Тогда в объявлении метода пишут оператор throws и в нём через запятую перечень возможных типов исключений. Пример:

Public void methodC(int a) throws AnException { //code; }

Метод может сам выбросить исключение. Для этого используют оператор throw и объект исключения в нём. Пример:

Public void methodC(int a) throws AnException { if(a < 10) { throw new AnException("Error in methodC"); } }

Если этом примере a < 10, то будет выброшено исключение AnException, так, как если бы здесь произошла соответствующая ошибка.

Выбросить исключение оператором throw можно и из тела оработчика другого исключения. Так возникает цепочка исключений (chained exceptions) . Пример:

Public void methodA() { try { methodB(); } catch(AnException e) { System.out.println(e.toString()); throw new NextException("methodA throws NextException."); } }

Все классы исключений восходят к классу Throwable . Непосредственными наследниками его являются классы Error и Exception . От Exception происходят RuntimeException и все классы контролируемых исключений.

Мы уже знаем, что исключения типа Error обрабатывает система, мы их обычно не касаемся.

Исключения типа RuntimeException говорят об ошибках в коде. Такие исключения могут обрабатываться, но лучше просто исправить ошибки кода.

Исключения типа Exception говорят о наличии проблем, но они не являются серьёзными системными. Такие ошибки следует обрабатывать.

Можно создавать свои классы исключений как прямых или нет наследков Exception . Принято к названиям таких классов добавлять слово Exception .

Если тип аргумента оператора catch есть Exception , то соотвестсвующий обработчик исключений сможет захватить все контролируемые исключения и исключения типа RuntimeException . Так можно поступить, если нет особых требований к обработчику или если могут возникнуть непредвиденные исключения. Но если требуется особый подход, то лучше использовать наследников Exception .

Как самому создать класс исключения?

Так как мы должны обрабатывать контролируемые исключения, то унаследуем наш класс от Exception .

Пример

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

Package exceptionTest.test; public class TestClass { public TestClass() { } public void methodC(int a) throws AnException { if(a < 10) { throw new AnException("Error in methodC"); } } public void methodB() throws AnException { methodC(1); } public void methodA() { try { methodB(); } catch(AnException e) { System.out.println(e.toString()); throw new NextException("methodA throws NextException."); } } public static void main(String args) { TestClass tc = new TestClass(); try { tc.methodA(); } catch(NextException ex) { System.out.println(ex.toString()); } finally { System.out.print("Message from finally: The end."); } } }

Класс исключения AnException:

Public class AnException extends Exception { private static final long serialVersionUID = 1L; private String exceptionMessage; AnException() { exceptionMessage = null; } AnException(String exceptionMessage) { this.exceptionMessage = exceptionMessage; } public String toString() { return "Message from AnException: " + exceptionMessage; } }

Класс исключения NextException:

Package exceptionTest.test; public class NextException extends RuntimeException { private static final long serialVersionUID = 1L; private String exceptionMessage; NextException() { exceptionMessage = null; } NextException(String exceptionMessage) { this.exceptionMessage = exceptionMessage; } public String toString() { return "Message from NextException: " + exceptionMessage; } }

  • Сергей Савенков

    какой то “куцый” обзор… как будто спешили куда то