Исключения Java и способы их обработки

Как разработчик Java вы должны хорошо разбираться в исключениях Java и их обработке.

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



Что такое исключения Java

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


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

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




Зачем нужна обработка исключений

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

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

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



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

Все исключения в Java должны быть дочерними по отношению к Exception класс, который сам является потомком Throwable класс.


Два основных подкласса Exception класс RuntimeException и IOException.



Исключение против ошибки

Другой дочерний класс Throwable класс - это Error класс. Однако ошибки отличаются от исключений.

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

StackOverflowError и OutOfMemoryError два примера ошибок Java.




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

Мы можем разделить исключения Java на две основные категории: проверил а также не отмечен исключения.

Проверенные исключения - это исключения, которые необходимо обработать в программе перед компиляцией. Если эти исключения не обрабатываются, программа не будет скомпилирована компилятором Java. Поэтому их также называют исключениями времени компиляции. IOExceptions являются хорошими примерами проверенных исключений.

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

Все классы, расширяющие RuntimeException class - это непроверенные исключения. Два примера таких классов: NullPointerException и ArrayIndexOutOfBoundsException.




Часто используемые методы в классе исключений

Мы рассмотрим несколько часто используемых методов в Java Exception класс:

  1. getMessage: возвращает сообщение, содержащее подробную информацию о произошедшем исключении.
  2. printStackTrace: возвращает трассировку стека возникшего исключения.
  3. toString: возвращает имя класса и сообщение, возвращаемое с getMessage метод.


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

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

попробуй поймать

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

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


Базовый синтаксис блока try-catch следующий:

try {
//exception-prone code } catch(Exception e) {
//error handling logic }

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

Мы увидим, как обращаться с IOExceptions брошенный FileReader класс в программе на Java.

Пример:

import java.io.FileReader; public class TryCatchBlockExample {
public static void main(String[] args) {

try {

FileReader file = new FileReader('source.txt');

file.read();
}
catch(Exception e) {

e.printStackTrace();
}
} }

Здесь мы использовали единственный блок catch для обработки FileNotFoundException выбрасывается при создании экземпляра FileReader класс и IOException брошенный read() метод FileReader класс.

Оба эти исключения являются потомками Exception класс.

Мы также можем использовать несколько операторов catch, чтобы перехватывать различные типы ошибок, возникающих из-за кода внутри одного оператора try. В предыдущем примере мы можем использовать один блок catch, чтобы поймать FileNotFoundException и еще один блок catch для IOException как показано в следующем фрагменте кода:

import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class TryCatchBlockExample {
public static void main(String[] args) {

try {

FileReader file = new FileReader('source.txt');

file.read();

file.close();
}
catch(FileNotFoundException e) {

e.printStackTrace();
}
catch(IOException e) {

e.printStackTrace();
}
} }

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

Если исключения не совпадают, они передаются второму оператору catch. Если имеется более двух операторов catch, этот процесс продолжается до тех пор, пока исключение не достигнет оператора catch, который улавливает его тип.

Поскольку FileNotFoundException является подтипом IOException, использующим второй оператор catch для перехвата FileNotFoundException не сработает. Он будет обработан первым оператором catch и никогда не достигнет второго оператора.

Примечание:Обязательно использовать по крайней мере один оператор catch с оператором try.

наконец-то

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

Затем код внутри finally Оператор реализуется независимо от того, происходит ли исключение. finally оператор всегда должен стоять в конце блока try-catch-finally.

Например, когда мы используем FileReader Чтобы прочитать файл, важно закрыть открытый файл в конце обработки независимо от того, возникнет ли исключение или нет. Чтобы гарантировать это, мы можем поместить код, закрывающий файл, внутри finally утверждение.

import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class TryCatchFinallyBlockExample {
public static void main(String[] args) {
FileReader file = null;
try {

file = new FileReader('source.txt');

file.read();
}
catch(FileNotFoundException e) {

e.printStackTrace();
}
catch(IOException e) {

e.printStackTrace();
}
finally {

file.close();
}
} }

Однако, если вы попытаетесь скомпилировать приведенный выше код, он не будет скомпилирован из-за необработанного IOException. Это потому, что close() метод FileReader класс также может бросать IOExceptions. Итак, мы должны поместить эту часть в другой блок попытки, например:

import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class TryCatchFinallyBlockExample {
public static void main(String[] args) {
FileReader file = null;

try {

file = new FileReader('source.txt');

file.read();
}
catch(FileNotFoundException e) {

e.printStackTrace();
}
catch(IOException e) {

e.printStackTrace();
}
finally {

try {


file.close();

}

catch(IOException e) {


e.printStackTrace();

}
}
} }

бросает

Обработка ошибок с помощью throws ключевое слово в Java очень просто. Фактически, при таком подходе вы не обрабатываете исключение в том месте, где оно возникает. Вместо этого мы выбрасываем исключение из текущего метода в метод, который вызвал текущий метод. Затем обработка ошибки становится обязанностью внешнего метода.

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

Пример:

import java.io.FileReader; import java.io.IOException; public class ThrowsExample {
public void readFile throws IOException {
FileReader file = new FileReader('source.txt');
file.read();
file.close();
} }

бросать

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

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

public class ThrowExample {
public void invalidate(int amount) throws Exception {
if (amount < 500) {

throw new Exception('Amount not sufficient');
}
} }


Пользовательские исключения

Помимо использования встроенных исключений Java, вы можете определять свои собственные исключения. Вы можете определить их как отмеченные или непроверенные исключения. Чтобы создать новое проверенное исключение, новое исключение должно расширять Exception класс.

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

В следующем примере кода мы создали определяемое пользователем проверенное исключение:

public class InvalidLengthException extends Exception {
private int length;
private String message;
public InvalidLengthException(int length, String message) {
this.length=length;
this.message=message;
}
public int getAmount() {
return this.length;
}
public String getMessage() {
return this.message;
} }

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

public class InputChecker {
private int minLength;
private int maxLength;
public InputChecker(int minLength, int maxLength) {
this.minLength=minLength;
this.maxLength=maxLength;
}
public void checkStringLength(String strInput) throws InvalidLengthException {
int strLength = strInput.length();
if (strLength maxLength){

throw new InvalidLengthException(strLength, 'Input should have maximum '+maxLength+' character');
}
} }

Если мы проверим длину строки с помощью InputChecker класс, он выдаст InvalidLengthException если длина строки ниже минимальной или выше максимальной.

public class Main {
public static void main(String[] args) {
InputChecker ic = new InputChecker(2, 7);
try {

ic.checkStringLength('longer than the maximum length');
}
catch(InvalidLengthException e) {

e.printStackTrace();
}
} }

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

InvalidLengthException: Input should have maximum 7 character
at InputChecker.checkStringLength(InputChecker.java:17)
at Main.main(Main.java:6)


Заключение

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