Исключения. Обработка ошибок.

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

Пример, попробуем 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. В программе мы никогда ничего про эти исключения не писали, но они иногда появлялись во время работы.