Исключениями или исключительными ситуациями (состояниями) называются ошибки, возникшие в программе во время её работы.
Все исключения в Java являются объектами. Поэтому они могут порождаться не только автоматически при возникновении исключительной ситуации, но и создаваться самим разработчиком.
Иерархия классов исключений:
Исключения делятся на несколько классов, но все они имеют общего предка — класс
Throwable
. Его потомками являются подклассы Exception
и Error
.
Исключения (Exceptions
) являются результатом проблем в программе, которые в принципе решаемы и предсказуемы. Например, произошло деление на ноль в целых числах.
Ошибки (Errors
) представляют собой более серьёзные проблемы, которые, согласно спецификации Java, не следует пытаться обрабатывать в собственной программе, поскольку они связаны с проблемами уровня JVM. Например, исключения такого рода возникают, если закончилась память, доступная виртуальной машине. Программа дополнительную память всё равно не сможет обеспечить для JVM.
В Java все исключения делятся на три типа: контролируемые исключения (checked
) и неконтролируемые исключения (unchecked
), к которым относятся ошибки (Errors
) и исключения времени выполнения (RuntimeExceptions
, потомок класса Exception
).
Контролируемые исключения представляют собой ошибки, которые можно и нужно обрабатывать в программе, к этому типу относятся все потомки класса Exception
(но не RuntimeException
).
Обработка исключения может быть произведена с помощью операторов try…catch
, либо передана внешней части программы. Например, метод может передавать возникшие в нём исключения выше по иерархии вызовов, сам его не обрабатывая.
Неконтролируемые исключения не требуют обязательной обработки, однако, при желании, можно обрабатывать исключения класса RuntimeException
.
Откомпилируем и запустим такую программу:
class Main {
public static void main(String[] args) {
int a = 4;
System.out.println(a/0);
}
}
В момент запуска на консоль будет выведено следующее сообщение:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.main(Main.java:4)
Из сообщения виден класс случившегося исключения — ArithmeticException
. Это исключение можно обработать:
class Main {
public static void main(String[] args) {
int a = 4;
try {
System.out.println(a/0);
} catch (ArithmeticException e) {
System.out.println("Произошла недопустимая арифметическая операция");
}
}
}
Теперь вместо стандартного сообщения об ошибке будет выполняться блок catch
, параметром которого является объект e соответствующего исключению класса (самому объекту можно давать любое имя, оно потребуется в том случае, если мы пожелаем снова принудительно выбросить это исключение, например, для того, чтобы оно было проверено каким-то ещё обработчиком).
В блок try
при этом помещается тот фрагмент программы, где потенциально может возникнуть исключение.
Одному try
может соответствовать сразу несколько блоков catch с разными классами исключений.
import java.util.Scanner;
class Main {
public static void main(String[] args) {
int[] m = {-1,0,1};
Scanner sc = new Scanner(System.in);
try {
int a = sc.nextInt();
m[a] = 4/a;
System.out.println(m[a]);
} catch (ArithmeticException e) {
System.out.println("Произошла недопустимая арифметическая операция");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Обращение по недопустимому индексу массива");
}
}
}
Если запустив представленную программу, пользователь введётся с клавиатуры 1 или 2, то программа отработает без создания каких-либо исключений.
Если пользователь введёт 0, то возникнет исключение класса ArithmeticException
, и оно будет обработано первым блоком catch
.
Если пользователь введёт 3, то возникнет исключение класса ArrayIndexOutOfBoundsException
(выход за приделы массива), и оно будет обработано вторым блоком catch
.
Если пользователь введёт нецелое число, например, 3.14, то возникнет исключение класса InputMismatchException
(несоответствие типа вводимого значение), и оно будет выброшено в формате стандартной ошибки, поскольку его мы никак не обрабатывали.
Можно, однако, добавить обработчик для класса Exception
, поскольку этот класс родительский для всех остальных контролируемых исключений, то он будет перехватывать любые из них (в том числе, и InputMismatchException
).
import java.util.Scanner;
class Main {
public static void main(String[] args) {
int[] m = {-1,0,1};
int a = 1;
Scanner sc = new Scanner(System.in);
try {
a = sc.nextInt();
m[a-1] = 4/a;
System.out.println(m[a]);
} catch (ArithmeticException e) {
System.out.println("Произошла недопустимая арифметическая операция");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Обращение по недопустимому индексу массива");
} catch (Exception e) {
System.out.println("Произошло ещё какое-то исключение");
}
}
}
Поскольку исключения построены на иерархии классов и подклассов, то сначала надо пытаться обработать более частные исключения и лишь затем более общие. То есть поставив первым (а не третьим) блок с обработкой исключения класса Exception
, мы бы никогда не увидели никаких сообщений об ошибке, кроме «Произошло ещё какое-то исключение» (все исключения перехватились бы сразу этим блоком и не доходили бы до остальных).
Необязательным добавлением к блокам try…catch
может быть блок finally
. Помещенные в него команды будут выполняться в любом случае, вне зависимости от того, произошло ли исключение или нет. При том, что при возникновении необработанного исключения оставшаяся после генерации этого исключения часть программы — не выполняется. Например, если исключение возникло в процессе каких-то длительных вычислений, в блоке finally
можно показать или сохранить промежуточные результаты.
Ссылка на первоисточник: Исключения и их обработка
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
1. Контролируемые исключения (checked)
2. Неконтролируемые исключения (unchecked), к которым относятся ошибки (Errors)
3. Исключения времени выполнения (RuntimeExceptions, потомок класса Exception).
на ДВА типа?