Исключения. Обработка ошибок.
Исключения используются в большинстве современных языков. Механизмы исключений и обработки исключений везде очень похожи. Они нужны для обработки ошибок, которые неизбежно возникают во время работы любой программы. Как ошибки обрабатывались до появления исключений:
Пример, попробуем cоздать файл hello.txt и записать в него фразу Hello World. Используем псевдо-язык:
var file = open("hello.txt");
//всегда могут быть ошибки: 1) нет диска 2) нет прав на запись или
чтение файла 3) недостаточно ресурсов системы 4) ...
Как понять, удалась ли операция?
надо написать иначе
int error_code = open("hello.txt", file)
в переменную файл записывается открытый файл, в переменную
error_code возвращается код ошибки. 0 - нет ошибки, другие
числа говорят, какая именно ошибка произошла
if (error_code != 0) {
println("Ошибка при открытии файла");
return; //завершить функцию
}
error_code = writeln(file, "Hello World!");
if (error_code != 0) {
println("Ошибка при записи в файл");
//тут еще надо закрыть файл. Скопировать весь кусок
//про закрытие файла
return;
}
error_code = close(file)
if (error_code != 0) {
println("Ошибка при закрытии файла");
return;
}
Как это же самое делается с исключениями (примерно)
try { //блок "try" - попытайся
//внутри пишем оптимистичный сценарий, как будто ошибок не
//возникает
var file = open("hello.txt");
writeln(file, "Hello World");
close(file);
} except (OpenError e) { //что если все-таки возникла ошибка
println("Ошибка открытия файла: " + e.getMessage());
//переменная e хранит информацию об ошибке, может
//сформировать понятное сообщение о том, что пошло не так
} except (FileError e) {
println("Ошибка при работе с файлом: " + e.getMessage());
}
Если в блоке try возникла ошибка, то блок завершается и управление передается в соответствующий except Опять проблема: файл не закроется, если случится ошибка
try {
var file = open("hello.txt");
writeln(file, "Hello World");
} except (OpenError e) {
println("Ошибка открытия файла: " + e.getMessage());
} except (FileError e) {
println("Ошибка при работе с файлом: " + e.getMessage());
} finally {
if (проверить, что file открыт)
close(file);
}
Блок finally выполняется всегда, независимо от того, была ошибка или нет.
Как устроены исключения в Java
Иерархия классов ошибок
Все возможные ошибки, которые могут возникнуть при выполнении
программы - наследники типа Throwable
Error extends Throwable - ошибки, после которых выполнение программы дальше фактически невозможно. Пример OutOfMemoryError extends Error
Exception extends Throwable - ошибки, которые скорее всего
захочется обработать и продолжить выполнение программы дальше.
Примеры: Не открылся файл, вышли за границу массива (a[-1]
),
NullPointerException (String s = null; File f = null; s.length() - появится NPE, потому что он появляется при обращении к методу,
полю значения null)
В Exception есть подкласс RuntimeException - ошибки, которые обрабатывать необязательно. А вот все остальные Exception должны в программе обрабатываться или не обрабатываться в явном виде.
NullPointerException, ArrayIndexOutOfBoundsException - примеры RuntimeException. В программе мы никогда ничего про эти исключения не писали, но они иногда появлялись во время работы.