JavaRush /Курсы /Java Syntax Pro /Исключения в Java-программах

Исключения в Java-программах

Java Syntax Pro
14 уровень , 1 лекция
Открыта

1. Исключения

Исключения в Java-программах

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

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

Когда в Java-программе возникает ошибка, например, деление на 0, происходят такие замечательные вещи:

Шаг первый

Создается специальный объект-исключение, в котором содержится информация о произошедшей ошибке.

Все в Java является объектом, и исключения — не исключение 🙂 Объекты-исключения имеют свои классы, и все их отличие от обычных классов в том, что они унаследованы от класса Throwable.

Шаг второй

Объект-исключение «выбрасывается». Не сильно удачное название. «Выбрасывание исключения» по своей сути больше похоже на включение пожарной сигнализации или оповещение «боевая тревога».

Когда в систему «выброшено исключение», нормальный режим работы программы прекращается, и начинается «работа по аварийному протоколу».

Шаг третий

Текущий метод, в котором возникло (выброшено) исключение, немедленно завершается. Исключение передается в вызывающий метод, который тоже немедленно завершается. И так по цепочке, пока не завершится метод main. Вместе с завершением метода main завершается и программа.

Пример:

Код Вывод на экран
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Внимание! Подготовка к концу света");
      конецСвета();
      System.out.println("Конец света успешно завершён");
   }

   public static void конецСвета()
   {
      System.out.println("Делаем что-то важное");
      поделим(0);
      System.out.println("Все отлично работает");
   }

   public static void поделим(int n)
   {
      System.out.println("Ничего страшного не произойдет: " + n);
      System.out.println(2 / n);
      System.out.println("Ничего страшного не произошло: " + n);
   }
}
Внимание! Подготовка к концу света
Делаем что-то важное
Ничего страшного не произойдет: 0

В 20-й строке возникла ошибка — деление на 0. Java-машина тут же создала исключение — объект класса ArithmeticException и «выбросила» его в систему.

Метод поделим() сразу завершился, поэтому на экран не вывелась строка Ничего страшного не произошло: 0. Программа вернулась в метод конецСвета(), и ситуация повторилась: в системе есть исключение, а значит, метод конецСвета() тоже аварийно завершается. Затем завершается метод main, и выполнение программы прекращается.

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


2. Перехват исключений try-catch

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

try
{
   код, где может возникнуть ошибка
}
catch(ТипИсключения имя)
{
   код обработки исключения
}

Эта конструкция называется блок try-catch.

Код, в котором могут возникнуть исключения, оборачивается в фигурные скобки, перед которыми пишется слово try (пытаться).

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

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

Пример:

Код Вывод на экран
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Адронный Коллайдер запущен");

      try
      {
         запуститьАдронныйКоллайдер(1);
         запуститьАдронныйКоллайдер(0);
      }
      catch(Exception e)
      {
         System.out.println("Ошибка! Перехвачено исключение");
         System.out.println("Планету засосало в черную дыру!");
      }

      System.out.println("Адронный Коллайдер остановлен");
   }

   public static void запуститьАдронныйКоллайдер(int n)
   {
      System.out.println("Все отлично работает: " + n);
      System.out.println(2/n);
      System.out.println("Никаких проблем нет: " + n);
   }
}
Адронный Коллайдер запущен
Все отлично работает: 1
2
Никаких проблем нет: 1
Все отлично работает: 0
Ошибка! Перехвачено исключение
Планету засосало в черную дыру!
Адронный Коллайдер остановлен


3. Несколько блоков catch

Несколько блоков catch

Теоретически внутри блока кода могут возникать самые различные исключения. Некоторые вы захотите обработать одним образом, другие — вторым, третьи вообще решите не обрабатывать.

Разработчики Java решили помочь вам и позволили писать после блока try не один блок catch, а несколько.

try
{
   код, где может возникнуть ошибка
}
catch(ТипИсключения1 имя1)
{
   код обработки исключения1
}
catch(ТипИсключения2 имя2)
{
   код обработки исключения2
}
   catch(ТипИсключения3 имя3)
{
   код обработки исключения3
}

Пример:

Код Вывод на экран
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Начало метода main");
      try
      {
         calculate(0);
      }
      catch(ArithmeticException e)
      {
         System.out.println("Было деление на 0");
      }
      catch(Exception e)
      {
         System.out.println("Перехвачено какое-то исключение");
      }

      System.out.println("Конец метода main");
   }

   public static void calculate(int n)
   {
      System.out.println("calculate начало: " + n);
      System.out.println(2/n);
      System.out.println("calculate конец: " + n);
   }
}
Начало метода main
calculate начало: 0
Было деление на 0
Конец метода main


4. Порядок блоков catch

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

Однако порядок блоков имеет значение.

Может быть ситуация, когда исключение захвачено несколькими блоками. В этом случае оно будет захвачено блоком catch, который идет раньше (ближе к блоку try).

Как же может возникнуть ситуация, что одно исключение могут захватить несколько блоков catch?

Все исключения объединены в единую иерархию с помощью наследования — см. схему.

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

Объект-исключение типа ArithmeticException может быть присвоен переменной типа ArithmeticException, а также переменным его классов-предков: RuntimeException, Exception и Throwable — см. схему.

Подробнее о наследовании и классах-предках мы поговорим на 21 уровне.

Вот этот код будет отлично компилироваться:

Преимущества наследования:
ArithmeticException ae    = new ArithmeticException();
RuntimeException runtime  = new ArithmeticException();
Exception exception       = new ArithmeticException();
Throwable trwbl           = new ArithmeticException();

Поэтому и перехватить исключение типа ArithmeticException можно блоками catch любым из 4-х приведенных выше типов.

Пример 1:

Код Вывод на экран
class Solution
{    public static void main(String[] args)
   {
      System.out.println("Начало метода main");
      try
      {
         calculate(0);
      }
      catch(ArithmeticException e)
      {
         System.out.println("Было деление на 0");
      }
      catch(Exception e)
      {
         System.out.println("Перехвачено какое-то исключение");
      }

      System.out.println("Конец метода main");
   }

   public static void calculate(int n)
   {
      System.out.println("calculate начало: " + n);
      System.out.println(2/n);
      System.out.println("calculate конец: " + n);
   }
}
Начало метода main
calculate начало: 0
Было деление на 0
Конец метода main

В данном примере исключение ArithmeticException может быть перехвачено и блоком catch(Exception e), и блоком catch(ArithmeticException e). Оно будет захвачено тем блоком, который идет ближе к блоку try — первым блоком catch.

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

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


Комментарии (273)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Кирилл Уровень 30
12 ноября 2025
Потрясающий лектор, я хз как он так делает, но доступно и глубоко объясняет
Руслан Уровень 46
20 августа 2025
Офигенная тема с исключениями!!!!
Никита Уровень 1
24 июля 2025
То ли у меня лыжи не едут, то ли... Один блок try, два блока catch - нигде больше в коде дополнительно их нет. Тест работает криво или я работаю криво? :)
Никита Уровень 1
24 июля 2025
В общем-то, в правильном решении я увидел, что все содержимое блока while оборачивается в try-catch, но нет такого условия в задании. Считаю, что это явный баг :)
bastichik Уровень 30
18 августа 2025
Странно, у меня и так сработало
Zhenya Volkov Уровень 34
1 октября 2025
у тебя один блок catch завернут во второй
Никита Уровень 1
1 октября 2025
один за другим идут, последовательно - оба связаны с одним и тем же try что значит один блок catch завернут во второй?
Zhenya Volkov Уровень 34
2 октября 2025
сорян что запутал, с телефона на работе смотрю. все норм на скрине.
Владимир Уровень 28
7 октября 2025
ошибка у тебя не в том что обернут не весь цикл while, а в том что ты ловишь не тот тип exception (IndexOutOfBoundsException вместо ArrayIndexOutOfBoundsException)
Никита Уровень 1
7 октября 2025
действительно, глаза, видимо, окончательно замылились, спасибо!
Alex Уровень 18
19 октября 2025
На мой взгляд блоки catch нужно поменять местами (так у меня программа сработала)
Anonymous #3585174 Уровень 33
8 июля 2025
like
19 апреля 2025
Выжимка полезных ссылок из всех комментариев: Иерархия наследования исключений, для тех, кто захотел распечатать: Ссылка на Краткую шпаргалка по сочетаниям клавиш в IntelliJ IDEA Статья про исключения Оочень емкий и полезный коммент от Anastasia Способы обработки исключений: Есть несколько способов обрабатывать исключительные ситуации 1 Не обрабатывать (только unchecked) 2 Использовать операторы try/catch/finally 3 Объявить в методе throws 4 Выбросить ошибку в коде: throw new Exception Если коротко: нужно обработать ошибку - используем try/catch, нужно вынуть ошибку и положить ее на уровень выше(пробросить) без обработки - используем throws throw - создает исключение, throws - указывает что может потенциально быть исключение Иерархия расположения блоков: При использовании нескольких блоков catch, рекомендуется располагать более конкретные исключения (например, ArithmeticException) перед более общими типами исключений (например, Exception). Это связано с тем, что если более общий тип исключения будет расположен перед более конкретным типом, то более конкретный блок catch никогда не будет достигнут, так как все соответствующие исключения уже будут перехвачены более общим блоком catch.
18 апреля 2025
Что это за ошибка такая StackOverFlowError?)) Мол ищи сразу на стековерфлоу?))
lusya 1 Уровень 32
3 апреля 2025
"код не скомпилируется, так как компилятор понимает, что в коде есть недосягаемые блоки кода" - объясните пожалуйста эту фразу.
4 апреля 2025
В данном случае это значит, что при написании блоков catch нужно придерживаться опредленной последовательности согласно иерархии исключений - от частного к общему. Например: в первом catch перехватывать ArrayIndexOutOfBoundException, во втором - RuntimeException, в третьем - Exception. Если последовательность перевернуть и расположить перехват Exception в первом по счету catch блоке, то последующие catch блоки никогда не выполнятся. Даже если будет выброшен ArrayIndexOutOfBoundException он будет перехвачен в первом блоке catch с Exception согласно иерархии исключений. Независимо от выполнения кода, эта ветка выполнения останется всегда недосягаемой и компилятор на это отреагирует ошибкой компиляции.
Alpha Уровень 31
12 апреля 2025
Пример для понимая (смотрим на схему иерархии исключений) и пробуем запустить данный код: Scanner keyboard = new Scanner(System.in); try { System.out.print("Введите целое число: "); int n = keyboard.nextInt(); } catch (Throwable e) { System.out.println("Исключение типа - 'Throwable'"); } catch (Exception e) { System.out.println("Недосягаемое исключение типа (из-за чего компилятор выдаст ошибку - 'java: exception java.lang.Exception has already been caught') - 'Exception'"); }
Алла Уровень 72
25 февраля 2025
Очень полезная лекция. Благодарю. Особенная благодарность лектору!!!
JaCat Уровень 16
23 февраля 2025
Мне одному кажется, что более правильная запись приведенная ниже, чем в правильном решении. Зачем оборачивать весь код в цикле while в try? В условии же написано проверяем только методы parseInt() и get().

while (true) {
            System.out.print(PROMPT_STRING);
            String input = scanner.nextLine();
            if (input.toLowerCase().equals(EXIT)) {
                break;
            }

            try {
                int studentId = Integer.parseInt(input);
                System.out.println(ANSWERING + studentsJournal.get(studentId));
            } catch (IndexOutOfBoundsException e) {
                System.out.println(NOT_EXIST);
            } catch (NumberFormatException e) {
                System.out.println(INTEGER_REQUIRED);
            }
        }
Anonymous #3525583 Уровень 28
11 января 2025
последнюю часть вообще не понял
Evgeniy Уровень 26
11 января 2025
Представь это как дом: Ты в лифте на последнем этаже N try {все нормально, выходишь на первом} catch{что-то не так и ты выходишь на каком-то этаже (больше 1 и меньше N) и заходишь в квартиру } *и перед глазами появляется ошибка НО на 2 этаже ошибка конкретного типа (1 квартира) на 3 этаже - ошибка более обширная (или 1 или 2 или 3 квартира) конкретно уже не знаешь ... на 5 этаже - у тебя уже может быть с 10 возможных (пояснений ошибки) Поэтому если нужно понять "какая именно ошибка", то в catch в первую очередь проверяй с самой "дальней" то-есть конкретно описывающей тип ошибки А зная что твоя ошибка это "какая-то конкретная", в методе catch { } описываешь что в этом случае необходимо сделать.