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

Материал из Викиконспекты
Перейти к: навигация, поиск
Строка 23: Строка 23:
 
====runtime exception====
 
====runtime exception====
 
Эти исключения обычно возникают в результате ошибок программирования, например, ошибки разработчика или неверное использование интерфейса приложения. Например, в случае выхода за границы массива метод бросит ''OutOfBoundsException''. Теоретически приложение может поймать это исключение, но разумнее исправить ошибку.
 
Эти исключения обычно возникают в результате ошибок программирования, например, ошибки разработчика или неверное использование интерфейса приложения. Например, в случае выхода за границы массива метод бросит ''OutOfBoundsException''. Теоретически приложение может поймать это исключение, но разумнее исправить ошибку.
== Введение ==
 
В языке <tex>Java</tex> исключения <tex>(Exceptions)</tex> и ошибки <tex>(Errors)</tex> являются объектами. Когда метод вызывает (бросает - throws) исключительную ситуацию, он на самом деле работает с объектом. Но такое происходит не с любыми объектами, а только с теми, которые наследуются от <tex>Throwable.</tex>
 
  
[[Файл:exceptions-throwable.gif]]
+
==Обработка исключений==
 +
Код, который может бросить исключения оборачивается в try-блок, после которого идут блоки catch и finally.
  
<tex>RuntimeException</tex>, <tex>Error</tex> и их наследников еще называют <tex>unchecked</tex> <tex>exception</tex>, а всех остальных наследников класса <tex>Exception -</tex> <tex>checked</tex> <tex> exception.</tex> <tex> Checked</tex> <tex> Exception</tex> обязывает пользователя обработать ее (использую конструкцию <tex> try-catch </tex>.) или же отдать на откуп обрамляющим методам, в таком случае к декларации метода, который бросает проверяемое <tex>(checked)</tex> исключение, дописывают конструкцию <tex>throws</tex>, например
+
Сatch-блоки обрабатывают исключения, указанные в качестве аргумента. Тип аргумента должен быть именем класса, унаследованного от ''Throwable''.
public Date parse(String source) throws ParseException { ... }
 
  
== Так когда же нужно бросать ошибки? ==
+
Код из блока finally выполнится в любом случае: при нормальном выходе из try, после обработки исключения или при выходе по команде return. Блок finally удобен для закрытия файлов и освобождения любых других ресурсов.
На этот вопрос можно ответить просто: если в методе возможна ситуация, которую метод не в состоянии обработать самостоятельно, он должен “бросать” ошибку. Но ни в коем случае нельзя использовать исключительные ситуации для управления ходом выполнения программы.
 
Чаще всего <tex>Exceptions</tex> бросаются при нарушении [[Программирование по контракту|контракта]] метода.
 
Нарушение контракта со стороны создателя метода - это, например, что-нибудь на подобии <tex>MethodNotImplementedYetException</tex>.
 
Пользователь метода может нарушить контракт, например, таким способом: на вход <tex>Integer.parseInt(String)</tex> подать строку с буквами и по заслугам получить <tex>NumberFormatException</tex>
 
  
== А что собственно бросать? ==
+
NB: Если JVM выйдет во время выполнения кода из try или catch, то finally блок может не выполниться. Также, например, если (?) выполняющий try или catch код прерван, то блок finally может не выполниться, даже если приложение продолжает работать.
Выбор не то чтобы сильно велик, но и не однозначен: <tex>checked,</tex>  <tex>unchecked</tex> <tex>(runtime)</tex>, <tex>unchecked</tex> <tex>(error).</tex>
 
В подавляющем большинстве случаев <tex>Error</tex> вам не понадобится. Это в основном критические ошибки (например, <tex>StackOverflowError</tex>), с которыми пусть работает JVM.
 
<tex>Checked</tex> <tex>Exceptions</tex>, как было написано выше, заставляет программиста-пользователя написать код для ее обработки или же описать метод как “вызывающий исключительную ситуацию”.
 
С <tex>unchecked</tex> <tex> exception</tex> можно поступить по-разному. В случае с такими ошибками, пользователь сам решает, будет он обрабатывать эту ошибку, или же нет (компилятор не заставляет это делать).
 
Можно написать следующее простое правило: если некоторый набор входящих в метод данных может привести к нарушению контракта, и вы считаете, что программисту-пользователю важно разобраться с этим (и что он сможет это сделать), описывайте метод с конструкцией <tex>throws</tex>, иначе бросайте <tex>unchecked</tex> <tex>exception.</tex>
 
  
== Как обрабатывать? ==
+
Код в блоке finally должен быть максимально простым: например, если внутри блока finally будет брошено какое-либо исключение или просто встретится оператор return, брошенное в блоке try исключение (если таковое было брошено) будет забыто.  
Обрабатывать ошибку лучше там, где она возникла. Если в данном фрагменте кода нет возможности принять решение, что делать с исключением, его нужно бросать дальше, пока не найдется нужный обработчик, либо поток выполнения программы не вылетит совсем.
 
  
class intException extends Exception {
+
import java.io.IOException;
  intException(String message){
+
 
      super(message);
+
public class ExceptionTest {
  }
+
 
}
+
    public static void main(String[] args) {
  class Number {
+
        try {
    int b;
+
            try {
    int division (int a) throws intExceprion{  
+
                throw new Exception("a");
        if (a == 0) throw new intException("Division by zero")
+
            } finally {
             else return this.b / a;
+
                throw new IOException("b");
        }
+
             }
  }
+
        } catch (IOException ex) {
try {
+
            System.err.println(ex.getMessage());
    int c = a.division(b);
+
        } catch (Exception ex) {
    // Безопасное использование результата.
+
            System.err.println(ex.getMessage());
} catch (intException e) {
+
        }
     // Обработка ошибки
+
     }
}
+
}
Также возможно делать несколько catch
+
 
  try {
+
После того, как было брошено первое исключение - new Exception("a") - будет выполнен блок finally, в котором будет брошено исключение new IOException("b"), именно оно будет поймано и обработано. Результатом его выполнения будет вывод в консоль ''b''. Исходное исключение теряется.   
    // Действия
+
 
  } catch (*Exception e) {
+
==Исключения в Java7+==
    // Обработка исключения
+
* обработка нескольких типов исключений в одном catch-блоке:
} catch (*Exception e) {
+
 
    // Обработка исключения
+
  catch (IOException|SQLException ex) {...}
} finally {
+
 
    // Действия при выходе
+
В таких случаях параметры являются ''final'', следовательно, нельзя присвоить им любое значение в блоке catch.
}
+
 
Блок <tex> finally </tex> выполняется в независимости от выполнения <tex> catch </tex>
+
* Try с ресурсами
 +
 
 +
Ресурс {{---}} это объект, который должен быть закрыт после завершения работы с ним.

Версия 05:27, 18 июня 2013

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

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

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

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

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

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

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


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

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

error

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

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

runtime exception

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

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

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

С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. Исходное исключение теряется.

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

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

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

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

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