Обработка ошибок и исключения — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
(Методы обработки ошибок)
(Исключения)
Строка 7: Строка 7:
  
 
==Исключения==
 
==Исключения==
{{Определение
+
В Java возможна обработка ошибок с помощью исключений, которые позволяют:
|definition=
+
 
Исключениями или исключительными ситуациями (состояниями) называются ошибки, возникшие в программе во время её работы.
+
*разделить обработку ошибок и сам алгоритм;
}}
+
*не загромождать код проверками возвращаемых значений;
Каждый раз, когда при выполнении программы происходит ошибка, создается объект-исключение, содержащий информацию об ошибке, включая её тип и состояние программы.
+
*обрабатывать ошибки на верхних уровнях, если на текущем уровне не хватает данных для обработки. Например, при написании универсальной процедуры чтения из файла невозможно заранее предусмотреть реакцию на ошибку, так как эта реакция зависит от использующей процедуру программы.
 +
Каждый раз, когда при выполнении программы происходит ошибка, создается объект-исключение, содержащий информацию об ошибке, включая её тип и состояние программы на момент возникновения ошибки.
 
После создания исключения среда выполнения пытается найти в стеке вызовов метод, который содержит код, обрабатывающий это исключение. Поиск начинается с метода, в котором произошла ошибка, и проходит через стек в обратном порядке вызова методов. Если не было найдено ни одного подходящего обработчика, выполнение программы завершается.
 
После создания исключения среда выполнения пытается найти в стеке вызовов метод, который содержит код, обрабатывающий это исключение. Поиск начинается с метода, в котором произошла ошибка, и проходит через стек в обратном порядке вызова методов. Если не было найдено ни одного подходящего обработчика, выполнение программы завершается.
  
Строка 18: Строка 19:
 
#Заполнение stack trace'а этого исключения.
 
#Заполнение stack trace'а этого исключения.
 
#Stack unwinding (раскрутка стека) в поисках нужного обработчика.
 
#Stack unwinding (раскрутка стека) в поисках нужного обработчика.
 +
 
==Типы исключений==
 
==Типы исключений==
 
===Проверяемые исключения===
 
===Проверяемые исключения===

Версия 13:56, 23 июня 2013

Методы обработки ошибок

  1. Не обрабатывать
  2. Коды возврата. Основная идея — в случае ошибки возвращать специальное значение, которое не может быть корректным. Минусом такого подхода является необходимость проверки на наличие ошибок внутри метода и возвращаемого значения каждый раз при вызове метода. Кроме того, не всегда возможно определить тип ошибки.
  3. Использовать флаг ошибки: при возникновении ошибки устанавливать флаг в соответствующее значение. Минусы такого подхода аналогичны минусам использования кодов возврата.
  4. Можно вызвать метод обработки ошибки и возвращать то, что вернет этот метод. Но в таком случае не всегда возможно проверить корректность результата вызова основного метода.
  5. В случае ошибки просто закрыть программу. Это приведет к потере данных, также невозможно понять, в каком месте возникла ошибка.

Исключения

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

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

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

Таким образом, механизм обработки исключений содержит следующие операции:

  1. Создание объекта-исключения.
  2. Заполнение stack trace'а этого исключения.
  3. Stack unwinding (раскрутка стека) в поисках нужного обработчика.

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

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

Проверяемые исключения(checked exception) — это те исключения, для которых java-машина проверяет, что они обработаны или что соответствующий метод может его бросить.

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

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


Все исключения, кроме классов Error и RuntimeException и их наследников, являются проверяемыми.

Непроверяемые исключения

error

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

В некоторых случаях ситуация не столь критична. Например, нехватка памяти, вызывающая java.lang.OutOfMemoryError. Если эта ошибка произошла в момент выделения большого объема памяти – например, при создании массива, – ее можно перехватить и попытаться выделить память в меньших объемах, изменив каким-то образом алгоритм, который будет эту память использовать.

runtime exception

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

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

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

try {

 // Код, который может сгенерировать исключение

}

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

try {

 // Код, который может сгенерировать исключение

} catch(Type1 id1) {

 // Обработка исключения Type1

} catch(Type2 id2) {

 // Обработка исключения Type2

}

Сatch-блоки обрабатывают исключения, указанные в качестве аргумента. Тип аргумента должен быть классом, унаследованного от Throwable.

Код из блока finally выполнится в любом случае: при нормальном выходе из try, после обработки исключения или при выходе по команде return. Блок finally удобен для закрытия файлов и освобождения любых других ресурсов.

NB: Если JVM выйдет во время выполнения кода из try или catch, то finally блок может не выполниться. Также, например, если поток выполняющий try или catch код прерван, то блок finally может не выполниться, даже если приложение продолжает работать.

Код в блоке finally должен быть максимально простым: например, если внутри блока finally будет брошено какое-либо исключение или просто встретится оператор return, брошенное в блоке try исключение (если таковое было брошено) будет забыто.

import java.io.IOException;

public class ExceptionTest {

   public static void main(String[] args) {
       try {
           try {
               throw new Exception("a");
           } finally {
               throw new IOException("b");
           }
       } catch (IOException ex) {
           System.err.println(ex.getMessage());
       } catch (Exception ex) {
           System.err.println(ex.getMessage());
       }
   }

}

После того, как было брошено первое исключение - new Exception("a") - будет выполнен блок finally, в котором будет брошено исключение new IOException("b"), именно оно будет поймано и обработано. Результатом его выполнения будет вывод в консоль b. Исходное исключение теряется.

Спецификация исключений

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

Спецификация исключения использует дополнительное ключевое слово throws, за которым следует список потенциальных типов исключений. Так что определение метода может выглядеть так:

void f() throws InterruptedException, IOException { //...

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

Исключения в Java7+

  • обработка нескольких типов исключений в одном catch-блоке:
catch (IOException|SQLException ex) {...}

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

  • Try с ресурсами позволяет прямо в try блоке объявлять необходимые ресурсы, которые по завершению блока будут коректно закрыты (с помощью метода close()). Любой объект реализующий java.lang.AutoCloseable может быть использован как ресурс.

static String readFirstLineFromFile(String path) throws IOException {

   try (BufferedReader br =
                  new BufferedReader(new FileReader(path))) {
       return br.readLine();
   }

}

В приведенном примере в качестве ресурса использутся объект класса BufferedReader, который будет закрыт вне зависимосити от того, как выполнится try-блок.

Можно объявлять несколько ресурсов, разделяя их точкой с запятой.

Во время закрытия ресурсов тоже может быть брошено исключение. В try-with-resources добавленна возможность хранения "подавленных" исключений, и брошенное try-блоком исключение имеет больший приоритет, чем исключения получившиеся во время закрытия. Получить последние можно вызовом метода Throwable.getSuppressed от исключения брошенного try-блоком.