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

Как программист новичок

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

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

есть какая-то обработка исключений, так что если вы когда-нибудь перейдете с Java

Вы можете взять большинство из этих советов с собой.

Понимание исключений Java

На Яве исключение является объектом, который указывает на что-то ненормальное (или «исключительное»), произошедшее во время выполнения вашего приложения. Такие исключения выброшены, что в основном означает создание объекта исключения (аналогично тому, как «вызываются» ошибки).

Прелесть в том, что ты можешь ловить генерируемые исключения, которые позволяют вам справиться с ненормальным состоянием и позволить вашему приложению продолжать работать, как будто ничего не пошло не так. Например, в то время как нулевой указатель в C может привести к сбою приложения, Java позволяет бросать и ловить Исключение нулевого указателяs перед тем, как нулевая переменная может вызвать сбой.

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

  • Исключение нулевого указателя
  • NumberFormatException
  • IllegalArgumentException
  • RuntimeException
  • IllegalStateException

Так что же происходит, когда вы бросаете исключение?

Во-первых, Java просматривает непосредственный метод, чтобы увидеть, есть ли код, который обрабатывает исключение, которое вы бросили. Если обработчик не существует, он смотрит на метод, который вызвал текущий метод, чтобы увидеть, существует ли там дескриптор. Если нет, то он смотрит на метод, вызвавший этот метод, а затем на следующий метод и т. Д. Если исключение не перехвачено, приложение печатает трассировку стека, а затем вылетает. (На самом деле это больше нюанс, чем просто сбой, но это сложная тема, выходящая за рамки этой статьи.)

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

Exception in thread "main" java.lang.NullPointerException
at com.example.myproject.Book.getTitle(Book.java:16)
at com.example.myproject.Author.getBookTitles(Author.java:25)
at com.example.myproject.Bootstrap.main(Bootstrap.java:14)

Мы можем многое почерпнуть из этого. Во-первых, исключение было Исключение нулевого указателя. Это произошло в GetTitle () метод в строке 16 Book.java. Этот метод был вызван из getBookTitles () на линии 25 Author.java. Этот метод был вызван из главный() на линии 14 Bootstrap.java. Как видите, знание всего этого облегчает отладку.

Но опять же, истинное преимущество исключений состоит в том, что вы можете «обрабатывать» ненормальное состояние, перехватывая исключение, исправляя ситуацию и возобновляя приложение без сбоев.

Использование исключений Java в коде

Допустим, у вас есть SomeMethod () это берет целое число и выполняет некоторую логику, которая может сломаться, если целое число меньше 0 или больше 100. Это может быть хорошим местом для создания исключения:

public void someMethod(int value) {
if (value  100) {
throw new IllegalArgumentException();
}
// ...
}

Для того, чтобы поймать это исключение, вам нужно пойти туда, где SomeMethod () называется и использовать блок try-catch:

public void callingMethod() {
try {
someMethod(200);
someOtherMethod();
} catch (IllegalArgumentException e) {
// handle the exception in here
}
// ...
}

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

В нашем примере мы входим в блок try и немедленно вызываем SomeMethod (). Поскольку 200 не между 0 и 100, IllegalArgumentException брошен Это сразу заканчивается исполнением SomeMethod (), пропускает остальную логику в блоке try (someOtherMethod () никогда не вызывается) и возобновляет выполнение в блоке catch.

Что будет, если мы позвоним SomeMethod (50) вместо? IllegalArgumentException никогда не будет брошен. SomeMethod () будет исполняться как обычно. Блок try будет выполняться как обычно, вызывая someOtherMethod () когда someMethod () завершается. когда someOtherMethod () заканчивается, блок улова будет пропущен и callingMethod () будет продолжаться

Обратите внимание, что вы можете иметь несколько блоков catch на каждый блок try:

public void callingMethod() {
try {
someMethod(200);
someOtherMethod();
} catch (IllegalArgumentException e) {
// handle the exception in here
} catch (NullPointerException e) {
// handle the exception in here
}
// ...
}

Также обратите внимание, что по желанию в конце концов Блок также существует:

public void method() {
try {
// ...
} catch (Exception e) {
// ...
} finally {
// ...
}
}

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

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

Обратите внимание, что вы можете иметь блок finally без блока catch:

public void method() {
try {
// ...
} finally {
// ...
}
}

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

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

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

Чтобы создать проверенное исключение, расширьте от исключение. Чтобы создать непроверенное исключение, расширьте от RuntimeException.

Любой метод, который выдает проверенное исключение, должен обозначать это в сигнатуре метода, используя бросает ключевое слово. Так как Java встроенный IOException является проверенным исключением, следующий код не будет компилироваться:

public void wontCompile() {
// ...
if (someCondition) {
throw new IOException();
}
// ...
}

Сначала вы должны объявить, что он выдает проверенное исключение:

public void willCompile() throws IOException {
// ...
if (someCondition) {
throw new IOException();
}
// ...
}

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

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

Официальная документация по Java имеет страницу по этому вопросу. Он суммирует разницу с кратким эмпирическим правилом: «Если разумно ожидать, что клиент восстановится после исключения, сделайте его проверенным исключением. Если клиент не может ничего сделать для восстановления после исключения, сделайте его непроверенным исключением ».

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

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

Рекомендации по использованию исключений Java

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

  • Предпочитаю конкретные исключения общим исключениям. использование NumberFormatException над IllegalArgumentException когда это возможно, в противном случае используйте IllegalArgumentException над RuntimeException когда возможно.
  • Никогда не лови Throwable! исключение класс на самом деле расширяется Throwable, и блок catch на самом деле работает с Throwable или любой класс, который расширяет Throwable. Тем не менее ошибка класс также расширяется Throwable, и вы никогда не хотите поймать ошибка так как ошибкаs указывают на серьезные неисправимые проблемы.
  • Никогда не лови исключение! InterruptedException продолжается исключение, так что любой блок, который ловит исключение также будет ловить InterruptedException, и это очень важное исключение, с которым вы не хотите связываться (особенно в многопоточных приложениях), если не знаете, что делаете. Если вы не знаете, какое исключение нужно ловить, постарайтесь ничего не ловить.
  • Используйте описательные сообщения для облегчения отладки. Когда вы бросаете исключение, вы можете предоставить строка сообщение в качестве аргумента. Это сообщение может быть доступно в блоке catch с помощью Exception.getMessage () метод, но если исключение никогда не перехватывается, сообщение также будет отображаться как часть трассировки стека.
  • Старайтесь не ловить и игнорировать исключения. Чтобы обойти неудобства проверенных исключений, многие новички и ленивые программисты установят блок catch, но оставят его пустым. Плохой! Всегда обрабатывайте это изящно, но если вы не можете, по крайней мере распечатайте трассировку стека, чтобы вы знали, что было сгенерировано исключение. Вы можете сделать это с помощью Exception.printStackTrace () метод.
  • Остерегайтесь злоупотребления исключениями. Когда у вас есть молоток, все выглядит как гвоздь. Когда вы впервые узнаете об исключениях, вы можете почувствовать себя обязанным превратить все в исключение… до такой степени, что большая часть потока управления вашего приложения сводится к обработке исключений. Помните, исключения предназначены для «исключительных» случаев!

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

, Не торопитесь.

Есть вопросы? Знаете какие-либо другие советы, связанные с исключениями, которые я пропустил? Поделитесь ими в комментариях ниже!

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