Исключения Java: вы справляетесь с ними правильно?

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

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

    за пределами массива означает программную ошибку. Удачной отладки!

  • Ошибка синтаксического анализа XML должна быть доведена до сведения пользователя, чтобы можно было исправить файл XML.
  • Программе не хватает памяти (возможно, при обработке большого файла) можно исправить, возможно, увеличив объем памяти, доступной для процесса Java.

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

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

На рисунке ниже показаны основные части иерархии исключений Java. Базовый класс Throwable который подклассифицируется в исключение а также ошибка. Учебный класс исключение для условий, связанных с программой, которые приложения могут поймать при попытке спасти ситуацию. Учебный класс ошибка, с другой стороны, для указания серьезных ошибок в среде выполнения Java, которые приложения не должны отлавливать. Вот некоторые примеры: OutOfMemoryError а также StackOverflowError.

Иерархия исключений

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

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

Следующий метод пытается создать FileReader из файла. Конструктор выдает проверенное исключение FileNotFoundException который должен быть обработан вызывающим кодом или объявлен как брошенный.

Следующий код не компилировать, поскольку он не делает ни того, ни другого.

private void loadFile(String filename)
{
FileReader in = new FileReader(filename);
}

Один из способов получить код для компиляции — обработать исключение (см. Ниже).

private void loadFile(String filename)
{
try {
FileReader in = new FileReader(filename)); {
} catch(FileNotFoundException ex) {
// handle exception here
}
}

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

private void loadFile(String filename) throws java.io.FileNotFoundException
{
FileReader in = new FileReader(filename)); {
}

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

Непроверенное исключение — это исключение из подкласса RuntimeException и не должны быть обработаны напрямую или объявлены как указано выше. Например, следующий код приводит к Исключение нулевого указателя, который является типом RuntimeException. Код, однако, компилируется без ошибок, так как Исключение нулевого указателя это непроверенное исключение.

private void handleEvent()
{
String name = null;
if ( name.length() > 0 ) {
}
}

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

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

В следующем примере кода показано, как обернуть исключение. Метод method_1 () бросает SQLException в своем теле. Чтобы код правильно компилировался, исключение должно быть объявлено как выброшенное.

private void method_1() throws SQLException {
...
throw new SQLException;
}

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

private void method_2() {
try {
method_1();
} catch(java.sql.SQLException ex) {
throw new RuntimeException(ex);
}
}

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

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

,

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

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 8, Size: 5
at java.util.ArrayList.rangeCheck(ArrayList.java:653)
at java.util.ArrayList.get(ArrayList.java:429)
at sample.sample1.main(sample1.java:24)

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

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

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

Следующий код записывает сообщение об ошибке в файл журнала.

private void loadConfig() {
try {
// invoke code which might generate an IOException
} catch(java.io.IOException ex) {
// handle exception here. May be log to a log file.
log.warning(ex.getMessage());
}
}

Когда исключение заключено в другое, вы можете получить упакованное исключение:

Throwable cause = ex.getCause();
log.warning("Underlying cause: " + cause.getMessage());

Вам нужно получить доступ к трассировке стека и, возможно, извлечь имя метода, вызвавшего его?

StringBuilder sbuf = new StringBuilder("Stack Trace: ");
for (StackTraceElement el : ex.getStackTrace()) {
sbuf.append(el.getClassName() + "." + el.getMethodName()).append("\n");
}
log.warning(sbuf.toString());

Или, может, зарегистрировать исключение и сбросить его?

try {
...
} catch(java.io.IOException ex) {
log.warning(ex.getMessage());
throw ex;
}

исключение класс обеспечивает printStackTrace () метод, который может напечатать трассировку стека к вашему собственному PrintStream (или же PrintWriter).

try {
...
} catch(java.io.IOException ex) {
PrintStream out = ...;
out.println(ex.getMessage());
ex.printStackTrace(out);
}

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

try {
// throws some exceptions here
} catch(java.io.IOException ex) {
// IOException specific handling here
} catch(java.sql.SQLException ex) {
// SQLException specific handling here
}

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

try {
// throws some exceptions here
} catch(java.io.IOException | java.sql.SQLException ex) {
// IOException and SQLException specific handling here
} catch(SAXException ex) {
// SAXException specific handling here
}

Очистка ресурсов с наконец

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

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

,

InputStream in = null;
try {
...
in = new FileInputStream(filename);
...
} catch(java.io.IOException ex) {
log.warning(ex.getMessage());
} finally {
// code here is executed on exiting the try block,
// whether normally or due to an exception
if ( in != null ) in.close();
}

Блок «Попробуйте с ресурсами»

Java 1.7 представила примерочных с-ресурсы конструкция, которая облегчает очистку ресурсов. Это выглядит так:

try( InputStream in = new FileInputStream(..) ) {
// code which uses the InputStream.
}

Когда код выходит из блока (чисто или из-за исключения), InputStream Переменная автоматически очищается.

Очистите несколько ресурсов, объявив все из них в заголовке блока.

try( InputStream in = new FileInputStream(..);
Connection con = ...; ) {
// code which uses the InputStream and the Connection.
}

Любой объект, чей класс реализует AutoCloseable Интерфейс может быть очищен таким образом. Следующий класс выполняет определенную очистку в близко() метод.

public class MyClass implements AutoCloseable {
public void close() {
// cleanup code here
}
}

Используйте экземпляр этого класса в примерочных с-ресурсы блок.

try( MyClass obj = new MyClass(..) ) {
// code which uses the MyClass object.
}

Некоторые часто встречающиеся исключения

Давайте теперь посмотрим на некоторые часто встречающиеся исключения.

  • IndexOutOfBoundsException (не отмечено): указывает, что индекс элемента, к которому осуществляется доступ, находится за пределами массива, строки и т. д.
  • SQLException (проверено): выброшено из-за ошибки базы данных.
  • IOException (проверено): ошибка доступа к файлу или ошибки, связанные с вводом и выводом.
  • InterruptedException (проверено): генерируется, когда выполнение потока прерывается.
  • SAXException (проверено): выбрасывается из-за ошибок синтаксического анализа XML.
  • Исключение нулевого указателя (не проверено): использование нуля там, где требуется объект.

Завершение

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

и помощь в решении вопросов на производстве.

У вас есть какие-либо связанные с исключениями военные истории? Если это так, сообщите нам об этом в разделе комментариев ниже.

Имиджевый кредит: Дмитрий Николаев через Shutterstock.com

Ссылка на основную публикацию
Adblock
detector