Изменения

Перейти к: навигация, поиск

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

9800 байт добавлено, 00:40, 2 марта 2019
Классификация исключений
Double f(Double a, Double b) {
<font color=navy>'''if '''</font> ((a == <font color=navy>'''null'''</font>) || (b == <font color=navy>'''null'''</font>)) { <font color=navy>'''return null'''</font>;
}
<font color=gray>//...</font> <font color=navy>'''if '''</font> (Math.''abs''(b) < <font color=purple>'''EPS'''</font>) { <font color=navy>'''return null'''</font>; } <font color=navy>'''else '''</font> { <font color=navy>'''return '''</font> a / b;
}
}
Double d = f(a, b);
<font color=navy>'''if '''</font> (d != <font color=navy>'''null'''</font>) { <font color=gray>//...</font> } <font color=navy>'''else '''</font> { <font color=gray>//...</font>
}
'''3.'''Использовать флаг ошибки: при возникновении ошибки устанавливать флаг в соответствующее значение:
<font color=navy>'''boolean '''</font> <font color=purple>'''error'''</font>;
Double f(Double a, Double b) {
<font color=navy>'''if '''</font> ((a == <font color=navy>'''null'''</font>) || (b == <font color=navy>'''null'''</font>)) { <font color=purple>'''error '''</font> = <font color=navy>'''true'''</font>; <font color=navy>'''return null'''</font>;
}
<font color=gray>//...</font> <font color=navy>'''if '''</font> (Math.''abs''(b) < <font color=purple>'''EPS'''</font>) { <font color=purple>'''error '''</font> = <font color= navy>'''true'''</font>; <font color=navy>'''return '''</font> b; } <font color=navy>'''else '''</font> { <font color=navy>'''return '''</font> a / b;
}
}
<font color=purple>'''error '''</font> = <font color= navy>'''false'''</font>;
Double d = f(a, b);
<font color=navy>'''if '''</font> (<font color=purple>'''error'''</font>) { <font color=gray>//...</font> } <font color=navy>'''else '''</font> { <font color=gray>//...</font> }
Минусы такого подхода аналогичны минусам использования кодов возврата.
'''4.'''Можно вызвать метод обработки ошибки и возвращать то, что вернет этот метод.
Double f(Double a, Double b) {
<font color=navy>'''if '''</font> ((a == <font color=navy>'''null'''</font>) || (b == <font color=navy>'''null'''</font>)) { <font color=navy>'''return '''</font> nullPointer();
}
<font color=gray>//...</font> <font color=navy>'''if '''</font> (Math.''abs''(b) < <font color=purple>'''EPS'''</font>) { <font color=navy>'''return '''</font> divisionByZero(); } <font color=navy>'''else '''</font> { <font color=navy>'''return '''</font> a / b;
}
}
'''5.'''В случае ошибки просто закрыть программу.
<font color=navy>'''if '''</font> (Math.''abs''(b) < <font color=purple>'''EPS'''</font>) { System.''exit''(<font color=navy>0</font>); <font color=navy>'''return this'''</font>;
}
Это приведет к потере данных, также невозможно понять, в каком месте возникла ошибка.
Double f(Double a, Double b) {
<font color=navy>'''if '''</font> ((a == <font color=navy>'''null'''</font>) || (b == <font color=navy>'''null'''</font>)) { <font color=navy>'''throw new '''</font> IllegalArgumentException(<font color=green>"arguments of f() are null"</font>);
}
<font color=grey>//...</font> <font color=navy>'''return '''</font> a / b;
}
Проверять <code>b</code> на равенство нулю уже нет необходимости, так как при делении на ноль метод бросит [[Обработка_ошибок_и_исключения#RuntimeException|непроверяемое исключение]] <code>ArithmeticException</code>.
==Классификация исключений==
Класс Java <code>Throwable</code> описывает все, что может быть брошено как исключение. Наследеники <code>Throwable</code> - <code>EcxeptionException</code> и <code>Error</code> - основные типы исключений. Также <code>RuntimeException</code>, унаследованный от <code>Exception</code>, является существенным классом.
[[Файл:Exceptions.png|400px|thumb|right|Иерархия стандартных исключений]]
===Проверяемые исключения===
Чтобы сгенерировать исключение используется ключевое слово <code>throw</code>. Как и любой объект в Java, исключения создаются с помощью <code>new</code>.
<font color=navy>'''if '''</font> (t == <font color=navy>'''null'''</font>) { <font color=navy>'''throw new '''</font> NullPointerException(<font color=green>"t = null"</font>);
}
Есть два стандартных конструктора для всех исключений: первый - конструктор по умолчанию, второй принимает строковый аргумент, поэтому можно поместить подходящую информацию в исключение.
 Возможна ситуация, когда одно исключение становится причиной другого. Для этого существуют два существует механизм exception chaining. Практически у каждого класса исключения есть конструктор, принимающий в качестве параметра <code>Throwable</code> – причину исключительной ситуации. Если же такого конструкторанет, то у которых параметры: причина; сообщение <code>Throwable</code> есть метод <code>initCause(Throwable)</code>, который можно вызвать один раз, и причинапередать ему исключение-причину.
Как и было сказано раньше, определение метода должно содержать список всех проверяемых исключений, которые метод может бросить. Также можно написать более общий класс, среди наследников которого есть эти исключения.
<font color=navy>'''void '''</font> f() <font color=navy>'''throws '''</font> InterruptedException, IOException { <font color=gray>//...</font>
===try-catch-finally===
Код, который может бросить исключения оборачивается в <code>try</code>-блок, после которого идут блоки <code>catch</code> и <code>finally</code>(Один из них может быть опущен).
<font color=navy>'''try '''</font> { <font color=gray>// Код, который может сгенерировать исключение</font>
}
Сразу после блока проверки следуют после обработчики исключений, которые объявляются ключевым словом <code>catch</code>.
<font color=navy>'''try '''</font> { <font color=gray>// Код, который может сгенерировать исключение</font> } <font color=navy>'''catch'''</font>(Type1 id1) { <font color=gray>// Обработка исключения Type1</font> } <font color=navy>'''catch'''</font>(Type2 id2) { <font color=gray>// Обработка исключения Type2</font>
}
Код из блока <code>finally</code> выполнится в любом случае: при нормальном выходе из <code>try</code>, после обработки исключения или при выходе по команде <code>return</code>.
'''NB:''' Если JVM выйдет во время выполнения кода из <code>try</code> или <code>catch</code>, то <code>finally</code> -блок может не выполниться. Также, например, если поток выполняющий <code>try</code> или <code>catch</code> код остановлен, то блок <code>finally</code> может не выполниться, даже если приложение продолжает работать.
Блок <code>finally</code> удобен для закрытия файлов и освобождения любых других ресурсов. Код в блоке <code>finally</code> должен быть максимально простым. Если внутри блока <code>finally</code> будет брошено какое-либо исключение или просто встретится оператор <code>return</code>, брошенное в блоке <code>try</code> исключение (если таковое было брошено) будет забыто.
<font color=navy>'''<tt>import</tt>'''</font> java.io.IOException;
<font color=navy>'''<tt>public class ExceptionTest'''</tt> </font> ExceptionTest {
<font color=navy>'''<tt>public static void</tt>'''</font> main(<tt>String[]</tt> args) { <font color=navy>'''<tt>try</tt>'''</font> { <font color=navy>'''<tt>try</tt>'''</font> { <font color=navy>'''<tt>throw new </tt>''' </font>Exception(<font color=green>"a")</ttfont>); } <font color=navy>'''<tt>finally</tt>'''</font> { <font color=navy>'''<tt>throw new IOException</tt>'''</font> IOException(<font color=green>"b"</font>);
}
} <font color=navy>'''<tt>catch '''</tt></font> (IOException ex)</tt> { System.<font color=purple>'''''err'''''</font>.println(ex.getMessage()); } <font color=navy>'''<tt>catch '''</tt></font> (Exception ex)</tt> { System.<font color=purple>'''''err'''''</font>.println(ex.getMessage());
}
}
После того, как было брошено первое исключение - <code>new Exception("a")</code> - будет выполнен блок <code>finally</code>, в котором будет брошено исключение <code>new IOException("b")</code>, именно оно будет поймано и обработано. Результатом его выполнения будет вывод в консоль <code>b</code>. Исходное исключение теряется.
 
===Обработка исключений, вызвавших завершение потока===
 
При использовании нескольких потоков бывают ситуации, когда поток завершается из-за исключения. Для того, чтобы определить с каким именно, начиная с версии Java 5 существует интерфейс <code>Thread.UncaughtExceptionHandler</code>. Его реализацию можно установить нужному потоку с помощью метода <code>setUncaughtExceptionHandler</code>. Можно также установить обработчик по умолчанию с помощью статического метода <code>Thread.setDefaultUncaughtExceptionHandler</code>.
 
Интерфейс <code>Thread.UncaughtExceptionHandler</code> имеет единственный метод <code>uncaughtException(Thread t, Throwable e)</code>, в который передается экземпляр потока, завершившегося исключением, и экземпляр самого исключения. Когда поток завершается из-за непойманного исключения, JVM запрашивает у потока <code>UncaughtExceptionHandler</code>, используя метод <code>Thread.getUncaughtExceptionHandler()</code>, и вызвает метод обработчика – <code>uncaughtException(Thread t, Throwable e)</code>. Все исключения, брошенные этим методом, игнорируются JVM.
===Информация об исключениях===
Чтобы определить собственное проверяемое исключение, необходимо создать наследника класса <code>java.lang.Exception</code>. Желательно, чтобы у исключения был конструкор, которому можно передать сообщение:
<font color=navy>'''public class '''</font> FooException <font color=navy>'''extends '''</font> Exception { <font color=navy>'''public '''</font> FooException() { <font color=navy>'''super'''</font>();
}
<font color=navy>'''public '''</font> FooException(String message) { <font color=navy>'''super'''</font>(message);
}
<font color=navy>'''public '''</font> FooException(String message, Throwable cause) { <font color=navy>'''super'''</font>(message, cause);
}
<font color=navy>'''public '''</font> FooException(Throwable cause) { <font color=navy>'''super'''</font>(cause);
}
}
==Исключения в Java7==
* обработка нескольких типов исключений в одном <code>catch</code>-блоке:
<code><font color=navy>'''catch'''</font></code> (<tt>IOException</tt> | <tt>SQLException</tt> ex) {...}
В таких случаях параметры неявно являются <code>final</code>, поэтому нельзя присвоить им другое значение в блоке <code>catch</code>.
Байт-код, сгенерированный компиляцией такого <code>catch</code>-блока будет короче, чем код нескольких <code>catch</code>-блоков.
* <code>Try </code> с ресурсами позволяет прямо в <code>try</code>-блоке объявлять необходимые ресурсы, которые по завершению блока будут корректно закрыты (с помощью метода <code>close()</code>). Любой объект реализующий <code>java.lang.AutoCloseable</code> может быть использован как ресурс.
<tt><font color=navy>'''static '''</font> String</tt> readFirstLineFromFile(String path) <tt><font color=navy>'''throws '''</font> IOException</tt> { <tt><font color=navy>'''try'''</font></tt> (<tt>BufferedReader</tt> br = <tt><font color=navy>'''new '''</font> BufferedReader(<font color=navy>'''new '''</font> FileReader</tt>(path))) { <tt><font color=navy>'''return'''</font></tt> br.readLine();
}
}
В приведенном примере в качестве ресурса использутся объект класса <code>BufferedReader</code>, который будет закрыт вне зависимосити от того, как выполнится <code>try</code>-блок.
Можно объявлять несколько ресурсов, разделяя их точкой с запятой:
<font color=navy>'''public static void '''</font> viewTable(Connection con) throws SQLException {
String query = <font color=green>"select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES"</font>;
<font color=navy>'''try '''</font> (Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery(query)) { <font color=gray>//Work with Statement and ResultSet</font> } <font color=navy>'''catch '''</font> (SQLException e) {
e.printStackTrace;
}
}
Во время закрытия ресурсов тоже может быть брошено исключение. В try-with-resources добавленна возможность хранения "подавленных" исключений, и брошенное <code>try</code>-блоком исключение имеет больший приоритет, чем исключения получившиеся во время закрытия. Получить последние можно вызовом метода <code>getSuppressed()</code> от исключения брошенного <code>try</code>-блоком.
* Перебрасывание исключений с улучшенной проверкой соответствия типов.
Компилятор Java SE 7 тщательнее анализирует перебрасываемые исключения. Рассмотрим следующий пример:
<font color=navy>'''static class '''</font> FirstException <font color=navy>'''extends '''</font> Exception { } <font color=navy>'''static class '''</font> SecondException <font color=navy>'''extends '''</font> Exception { }
<font color=navy>'''public void '''</font> rethrowException(String exceptionName) <font color=navy>'''throws '''</font> Exception { <font color=navy>'''try '''</font> { <font color=navy>'''if '''</font> (exceptionName<font color=green>"First"</font>.equals("First"exceptionName)) { <font color=navy>'''throw new '''</font> FirstException(); } <font color=navy>'''else '''</font> { <font color=navy>'''throw new '''</font> SecondException();
}
} <font color=navy>'''catch '''</font> (Exception ex) { <font color=navy>'''throw '''</font> e;
}
}
В примере <code>try</code>-блок может бросить либо <code>FirstException</code>, либо <code>SecondException</code>. В версиях до Java SE 7 невозможно указать эти исключения в декларации метода, потому что <code>catch</code>-блок перебрасывает исключение <code>ex</code>, тип которого - <code>Exception</code>.
В Java SE 7 вы можете указать, что метод <code>rethrowException</code> бросает только <code>FirstException</code> и <code>SecondException</code>. Компилятор определит, что исключение <code>Exception ex</code> могло возникнуть только в <code>try</code>-блоке, в котором может быть брошено <code>FirstException</code> или <code>SecondException</code>. Даже если тип параметра <code>catch </code> - <code>Exception</code>, компилятор определит , что это экземпляр либо <code>FirstException</code>, либо <code>SecondException</code>:
<font color=navy>'''public void '''</font> rethrowException(String exceptionName) <font color=navy>'''throws '''</font> FirstException, SecondException { <font color=navy>'''try '''</font> { <font color=gray>// ...</font> } <font color=navy>'''catch '''</font> (Exception e) { <font color=navy>'''throw '''</font> e;
}
}
* <code>IllegalArgumentException</code> используется для того, чтобы избежать передачи некорректных значений аргументов. Например:
<tt><font color=navy>'''public void'''</font></tt> f(<tt>Object</tt> a) { <tt><font color=navy>'''if'''</font></tt> (a == <tt><font color=navy>'''null'''</font></tt>) { <tt><font color=navy>'''throw new NullPointerException'''</font> IllegalArgumentException</tt>(<font color=green>"a must not be null"</font>);
}
}
*<code>IllegalStateException</code> возникает в результате некорректного состояния объекта. Например, использование объекта перед тем как он будет инициализирован.
 
==Гарантии безопасности==
При возникновении исключительной ситуации, состояния объектов и программы могут удовлетворять некоторым условиям, которые определяются различными типами гарантий безопасности:
* Отсутствие гарантий (''no exceptional safety''). Если было брошено исключение, то не гарантируется, что все ресурсы будут корректно закрыты и что объекты, методы которых бросили исключения, могут в дальнейшем использоваться. Пользователю придется пересоздавать все необходимые объекты и он не может быть уверен в том, что может переиспозовать те же самые ресурсы.
* Отсутствие утечек (''no-leak guarantee''). Объект, даже если какой-нибудь его метод бросает исключение, освобождает все ресурсы или предоставляет способ сделать это.
* Слабые гарантии (''weak exceptional safety''). Если объект бросил исключение, то он находится в корректном состоянии, и все инварианты сохранены. Рассмотрим пример:
 
<font color=navy>'''class'''</font> Interval {
<font color=gray>//invariant: left <= right</font>
double left;
double right;
<font color=gray>//...</font>
}
 
Если будет брошено исключение в этом классе, то тогда гарантируется, что ивариант "левая граница интервала меньше правой" сохранится, но значения <code>left</code> и <code>right</code> могли измениться.
 
* Сильные гарантии (''strong exceptional safety''). Если при выполнении операции возникает исключение, то это не должно оказать какого-либо влияния на состояние приложения. Состояние объектов должно быть таким же как и до вызовов методов.
 
* Гарантия отсутствия исключений (''no throw guarantee''). Ни при каких обстоятельствах метод не должен генерировать исключения. В Java это невозможно, например, из-за того, что <code>VirtualMachineError</code> может произойти в любом месте, и это никак не зависит от кода. Кроме того, эту гарантию практически невозможно обеспечить в общем случае.
==Источники==
*[http://www.kgeorgiy.info/courses/java-intro/lectures/exceptions.html Обработка ошибок и исключения {{---}} Сайт Георгия Корнеева]*[http://www.lektorium.tv/lecture/13377 Лекция Георгия Корнеева {{---}} Лекториум]*[http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html The Java Tutorials. Lesson: Exceptions.]
*[http://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9 Обработка исключений {{---}} Википедия]
*[http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html Throwable (Java Platform SE 7 ) {{- --}} Oracle Documentation]*[http://www.skipy.ru/technics/exceptions.html try/catch/finally и исключения {{---}} www.skipy.ru]
[[Категория: Язык программирования Java]]
Анонимный участник

Навигация