0 added
0 removed
Original
2026-01-01
Modified
2026-02-21
1
<p><a>#База знаний</a></p>
1
<p><a>#База знаний</a></p>
2
<ul><li>24 фев 2021</li>
2
<ul><li>24 фев 2021</li>
3
<li>0</li>
3
<li>0</li>
4
</ul><p>Разбираемся, что такое исключения, зачем они нужны и как с ними работать.</p>
4
</ul><p>Разбираемся, что такое исключения, зачем они нужны и как с ними работать.</p>
5
<p> vlada_maestro / shutterstock</p>
5
<p> vlada_maestro / shutterstock</p>
6
<p>Хлебом не корми - дай кому-нибудь про Java рассказать.</p>
6
<p>Хлебом не корми - дай кому-нибудь про Java рассказать.</p>
7
<p>Из этой статьи вы узнаете:</p>
7
<p>Из этой статьи вы узнаете:</p>
8
<ul><li>что такое исключения (Exceptions);</li>
8
<ul><li>что такое исключения (Exceptions);</li>
9
<li>как они возникают и чем отличаются от ошибок (Errors);</li>
9
<li>как они возникают и чем отличаются от ошибок (Errors);</li>
10
<li>зачем нужна конструкция try-catch;</li>
10
<li>зачем нужна конструкция try-catch;</li>
11
<li>как разобраться в полученном исключении</li>
11
<li>как разобраться в полученном исключении</li>
12
<li>и как вызвать исключение самому.</li>
12
<li>и как вызвать исключение самому.</li>
13
</ul><p>Код вашей программы исправно компилируется и запускается, только вот вместо желанного результата вы видите непонятный текст. Строчки его будто кричат на вас, аж побагровели.</p>
13
</ul><p>Код вашей программы исправно компилируется и запускается, только вот вместо желанного результата вы видите непонятный текст. Строчки его будто кричат на вас, аж побагровели.</p>
14
<p>За примером далеко ходить не надо: сделаем то, что нам запрещали ещё в школе, - поделим на ноль.</p>
14
<p>За примером далеко ходить не надо: сделаем то, что нам запрещали ещё в школе, - поделим на ноль.</p>
15
public static void main(String[] args) { hereWillBeTrouble(42, 0); } public static void hereWillBeTrouble(int a, int b) { int oops = a / b; System.out.println(oops); }<p>А получим вот что:</p>
15
public static void main(String[] args) { hereWillBeTrouble(42, 0); } public static void hereWillBeTrouble(int a, int b) { int oops = a / b; System.out.println(oops); }<p>А получим вот что:</p>
16
<p>Это и есть исключение.</p>
16
<p>Это и есть исключение.</p>
17
<p><strong>"Исключение" - сокращение от слов "исключительный случай". Это ситуация, в которой программа не может продолжить работу или её работа становится бессмысленной.</strong>Причём речь не только о нештатных ситуациях - исключения бывают и намеренными, такие разработчик вызывает сам.</p>
17
<p><strong>"Исключение" - сокращение от слов "исключительный случай". Это ситуация, в которой программа не может продолжить работу или её работа становится бессмысленной.</strong>Причём речь не только о нештатных ситуациях - исключения бывают и намеренными, такие разработчик вызывает сам.</p>
18
<p><strong>Это интересно.</strong>Исключения в Java появились уже в первой версии языка. А вот в языках, где их нет, вместо них возвращают коды ошибок.</p>
18
<p><strong>Это интересно.</strong>Исключения в Java появились уже в первой версии языка. А вот в языках, где их нет, вместо них возвращают коды ошибок.</p>
19
<p>У всех классов исключений есть общий класс-предок Throwable, от него наследуются классы Error и Exception, базовые для всех прочих.</p>
19
<p>У всех классов исключений есть общий класс-предок Throwable, от него наследуются классы Error и Exception, базовые для всех прочих.</p>
20
Верхушка иерархии исключений Java<p><strong>Error -</strong><strong>это критические условия, в которых работа программы должна быть завершена</strong><strong>.</strong>Например, когда при выполнении программы закончилась память, произошёл сбой в системе или виртуальной машине. Не будем задерживаться на этой ветке, поскольку документация Java говорит:</p>
20
Верхушка иерархии исключений Java<p><strong>Error -</strong><strong>это критические условия, в которых работа программы должна быть завершена</strong><strong>.</strong>Например, когда при выполнении программы закончилась память, произошёл сбой в системе или виртуальной машине. Не будем задерживаться на этой ветке, поскольку документация Java говорит:</p>
21
<p>Error is the superclass of all the exceptions from which ordinary programs are not ordinarily expected to recover.</p>
21
<p>Error is the superclass of all the exceptions from which ordinary programs are not ordinarily expected to recover.</p>
22
<p>Что в переводе означает:<em></em><strong>ошибки (Error)</strong><em> - это такие исключительные ситуации, в которых восстанавливать работу программы не предполагается</em>.</p>
22
<p>Что в переводе означает:<em></em><strong>ошибки (Error)</strong><em> - это такие исключительные ситуации, в которых восстанавливать работу программы не предполагается</em>.</p>
23
<p>То есть это проблемы, которые нельзя (недопустимо) исправлять на ходу. Всё, что нам остаётся, - извиниться перед пользователем и впредь писать программы, где возникнет меньше подобных ситуаций. Например, не допускать такой глубокой рекурсии, как в коде ниже:</p>
23
<p>То есть это проблемы, которые нельзя (недопустимо) исправлять на ходу. Всё, что нам остаётся, - извиниться перед пользователем и впредь писать программы, где возникнет меньше подобных ситуаций. Например, не допускать такой глубокой рекурсии, как в коде ниже:</p>
24
static void notGood() { System.out.println("Только не снова!"); notGood(); }<p>При работе этого метода у нас возникнет ошибка: Exception in thread "main" java.lang.StackOverflowError - стек вызовов переполнился, так как мы не указали условие выхода из рекурсии.</p>
24
static void notGood() { System.out.println("Только не снова!"); notGood(); }<p>При работе этого метода у нас возникнет ошибка: Exception in thread "main" java.lang.StackOverflowError - стек вызовов переполнился, так как мы не указали условие выхода из рекурсии.</p>
25
<p>А теперь об <strong>Exception</strong>. Эти исключительные ситуации возникают, если разработчик допустил невыполнимую операцию, не предусмотрел особые случаи в бизнес-логике программы (или сообщает о них с помощью исключений).</p>
25
<p>А теперь об <strong>Exception</strong>. Эти исключительные ситуации возникают, если разработчик допустил невыполнимую операцию, не предусмотрел особые случаи в бизнес-логике программы (или сообщает о них с помощью исключений).</p>
26
<p>1. Невыполнимая операция</p>
26
<p>1. Невыполнимая операция</p>
27
<p>Мир не рухнул, как в случае с Error, просто Java не знает, что делать дальше. Как раз из этого разряда деление на ноль в начале статьи: и правда, какое значение тогда присвоить переменной oops?</p>
27
<p>Мир не рухнул, как в случае с Error, просто Java не знает, что делать дальше. Как раз из этого разряда деление на ноль в начале статьи: и правда, какое значение тогда присвоить переменной oops?</p>
28
<p>Убедитесь сами, что исключение класса ArithmeticException наследуется как раз от Exception.</p>
28
<p>Убедитесь сами, что исключение класса ArithmeticException наследуется как раз от Exception.</p>
29
<p><strong>Стоит запомнить.</strong>В IntelliJ IDEA, чтобы увидеть положение класса в иерархии, выберите его и нажмите Ctrl + H (или на пункт Type Hierarchy в меню Navigate).</p>
29
<p><strong>Стоит запомнить.</strong>В IntelliJ IDEA, чтобы увидеть положение класса в иерархии, выберите его и нажмите Ctrl + H (или на пункт Type Hierarchy в меню Navigate).</p>
30
<p>Другая частая ситуация - обращение к несуществующему элементу массива. Например, у нас в нём десять элементов, а мы пытаемся обратиться к одиннадцатому.</p>
30
<p>Другая частая ситуация - обращение к несуществующему элементу массива. Например, у нас в нём десять элементов, а мы пытаемся обратиться к одиннадцатому.</p>
31
<p>2. Особый случай в бизнес-логике программы</p>
31
<p>2. Особый случай в бизнес-логике программы</p>
32
<p>Классика. Программируем задачу о перевозке волка, козы и капусты через реку: в лодке может быть только два пассажира, но волка с козой и козу с капустой нельзя оставлять на берегу вместе. Это и есть особый случай в бизнес-логике, который нельзя нарушать.</p>
32
<p>Классика. Программируем задачу о перевозке волка, козы и капусты через реку: в лодке может быть только два пассажира, но волка с козой и козу с капустой нельзя оставлять на берегу вместе. Это и есть особый случай в бизнес-логике, который нельзя нарушать.</p>
33
<p>Или пользователь вводит дату начала некоторого периода и дату его окончания. Вторая дата не может быть раньше первой.</p>
33
<p>Или пользователь вводит дату начала некоторого периода и дату его окончания. Вторая дата не может быть раньше первой.</p>
34
<p>Или, допустим, у нас есть метод, который читает файл. Сам метод написан верно. Пользователь передал в него корректный путь. Только вот у этого работника нет права читать этот файл (его роль и права обусловлены предметной областью). Что же тогда методу возвращать? Вернуть-то нечего, ведь метод не отработал. Самое очевидное решение - выдать исключение.</p>
34
<p>Или, допустим, у нас есть метод, который читает файл. Сам метод написан верно. Пользователь передал в него корректный путь. Только вот у этого работника нет права читать этот файл (его роль и права обусловлены предметной областью). Что же тогда методу возвращать? Вернуть-то нечего, ведь метод не отработал. Самое очевидное решение - выдать исключение.</p>
35
<p>В дерево исключений мы <a>ещё углубимся</a>, а сейчас посмотрим, что и как с ними делают.</p>
35
<p>В дерево исключений мы <a>ещё углубимся</a>, а сейчас посмотрим, что и как с ними делают.</p>
36
<p><strong>Простейший вариант</strong> - ничего; возникает исключение - программа просто прекращает работать.</p>
36
<p><strong>Простейший вариант</strong> - ничего; возникает исключение - программа просто прекращает работать.</p>
37
<p>Чтобы убедиться в этом, выполним код:</p>
37
<p>Чтобы убедиться в этом, выполним код:</p>
38
public static void main(String[] args) { hereWillBeTrouble(42, 0); } public static void hereWillBeTrouble(int a, int b) { System.out.println("Всё, что было до..."); int oops = a / b; System.out.println(oops); System.out.println("Всё, что будет после..."); }<p>Так и есть: до деления на ноль код выполнялся, а после - нет.</p>
38
public static void main(String[] args) { hereWillBeTrouble(42, 0); } public static void hereWillBeTrouble(int a, int b) { System.out.println("Всё, что было до..."); int oops = a / b; System.out.println(oops); System.out.println("Всё, что будет после..."); }<p>Так и есть: до деления на ноль код выполнялся, а после - нет.</p>
39
<p><strong>Это интересно:</strong>когда возникает исключение, программисты выдают что-то вроде "код<em>[вы]бросил</em>исключение" или "код<em>кинул</em>исключение". А глагол таков потому, что все исключения - наследники класса Throwable, что значит "бросаемый" / "который можно бросить".</p>
39
<p><strong>Это интересно:</strong>когда возникает исключение, программисты выдают что-то вроде "код<em>[вы]бросил</em>исключение" или "код<em>кинул</em>исключение". А глагол таков потому, что все исключения - наследники класса Throwable, что значит "бросаемый" / "который можно бросить".</p>
40
<p><strong>Второе, что можно делать с исключениями,</strong> - это их обрабатывать.</p>
40
<p><strong>Второе, что можно делать с исключениями,</strong> - это их обрабатывать.</p>
41
<p>Для этого нужно заключить кусок кода, который может вызвать исключение, в конструкцию try-catch.</p>
41
<p>Для этого нужно заключить кусок кода, который может вызвать исключение, в конструкцию try-catch.</p>
42
<p><strong>Как это работает:</strong>если в блоке try возникает исключение, которое указано в блоке catch, то исполнение блока try прервётся и выполнится код из блока catch.</p>
42
<p><strong>Как это работает:</strong>если в блоке try возникает исключение, которое указано в блоке catch, то исполнение блока try прервётся и выполнится код из блока catch.</p>
43
<p>Например:</p>
43
<p>Например:</p>
44
public static void main(String[] args) { hereWillBeTrouble(); } private static void hereWillBeTrouble(int a, int b) { int oops; try { System.out.println("Всё, что было до..."); oops = a / b; System.out.println(oops); System.out.println("Всё, что будет после..."); } catch (ArithmeticException e) { System.out.println("Говорили же не делить на ноль!"); oops = 0; } System.out.println("Метод отработал"); }<p>Разберём этот код.</p>
44
public static void main(String[] args) { hereWillBeTrouble(); } private static void hereWillBeTrouble(int a, int b) { int oops; try { System.out.println("Всё, что было до..."); oops = a / b; System.out.println(oops); System.out.println("Всё, что будет после..."); } catch (ArithmeticException e) { System.out.println("Говорили же не делить на ноль!"); oops = 0; } System.out.println("Метод отработал"); }<p>Разберём этот код.</p>
45
<p>Если блок try кинет исключение ArithmeticException, то управление перехватит блок catch, который выведет строку "Говорили же не делить на ноль!", а значение oops станет равным 0.</p>
45
<p>Если блок try кинет исключение ArithmeticException, то управление перехватит блок catch, который выведет строку "Говорили же не делить на ноль!", а значение oops станет равным 0.</p>
46
<p>После этого программа продолжит работать как ни в чём не бывало: выполнится код после блока try-catch, который сообщит: "Метод отработал".</p>
46
<p>После этого программа продолжит работать как ни в чём не бывало: выполнится код после блока try-catch, который сообщит: "Метод отработал".</p>
47
<p>Проверьте сами: запустите код выше. Вызовите метод hereWillBeTrouble с любыми значениями аргументов кроме нулевого b. Если в блоке try не возникнет исключений, то его код выполнится целиком, а в блок catch мы даже не попадём.</p>
47
<p>Проверьте сами: запустите код выше. Вызовите метод hereWillBeTrouble с любыми значениями аргументов кроме нулевого b. Если в блоке try не возникнет исключений, то его код выполнится целиком, а в блок catch мы даже не попадём.</p>
48
<p><strong>Есть ещё и третий вариант</strong> - пробросить исключение наверх. Но об этом в <a>следующей</a>статье.</p>
48
<p><strong>Есть ещё и третий вариант</strong> - пробросить исключение наверх. Но об этом в <a>следующей</a>статье.</p>
49
<p>Вернёмся к первой картинке. Посмотрим, что нам сказала Java, когда произошло исключение:</p>
49
<p>Вернёмся к первой картинке. Посмотрим, что нам сказала Java, когда произошло исключение:</p>
50
<p>Начинаем разбирать сверху вниз:</p>
50
<p>Начинаем разбирать сверху вниз:</p>
51
<p>- это указание на поток, в котором произошло исключение. В нашей простой однопоточной программе это поток main.</p>
51
<p>- это указание на поток, в котором произошло исключение. В нашей простой однопоточной программе это поток main.</p>
52
<p>- какое исключение брошено. У нас это ArithmeticException. А java.lang.ArithmeticException - полное название класса вместе с пакетом, в котором он размещается.</p>
52
<p>- какое исключение брошено. У нас это ArithmeticException. А java.lang.ArithmeticException - полное название класса вместе с пакетом, в котором он размещается.</p>
53
<p>- весточка, которую принесло исключение. Дело в том, что одно и то же исключение нередко возникает по разным причинам. И тут мы видим стандартное пояснение "/ by zero" - из-за<em>деления на ноль</em>.</p>
53
<p>- весточка, которую принесло исключение. Дело в том, что одно и то же исключение нередко возникает по разным причинам. И тут мы видим стандартное пояснение "/ by zero" - из-за<em>деления на ноль</em>.</p>
54
<p>- это самое интересное: стектрейс.</p>
54
<p>- это самое интересное: стектрейс.</p>
55
<p><strong>Стектрейс (Stack trace) - это упорядоченный список методов, сквозь которые исключение пронырнуло.</strong></p>
55
<p><strong>Стектрейс (Stack trace) - это упорядоченный список методов, сквозь которые исключение пронырнуло.</strong></p>
56
<p>У нас оно возникло в методе hereWillBeTrouble на 8-й строке в классе Main (номер строки и класс указаны в скобках синим). А этот метод, в свою очередь, вызван методом main на 3-й строке класса Main.</p>
56
<p>У нас оно возникло в методе hereWillBeTrouble на 8-й строке в классе Main (номер строки и класс указаны в скобках синим). А этот метод, в свою очередь, вызван методом main на 3-й строке класса Main.</p>
57
<p>Стектрейсы могут быть довольно длинными - из десятков методов, которые вызывают друг друга по цепочке. И они здорово помогают расследовать неожиданно кинутое исключение.</p>
57
<p>Стектрейсы могут быть довольно длинными - из десятков методов, которые вызывают друг друга по цепочке. И они здорово помогают расследовать неожиданно кинутое исключение.</p>
58
<p>Советую закреплять теорию на практике. Поэтому вернитесь в блок про Error и вызовите метод notGood - увидите любопытный стектрейс.</p>
58
<p>Советую закреплять теорию на практике. Поэтому вернитесь в блок про Error и вызовите метод notGood - увидите любопытный стектрейс.</p>
59
<p>Всё это время мы имели дело с исключением, которое бросает Java-машина - при делении на ноль. Но как вызвать исключение самим?</p>
59
<p>Всё это время мы имели дело с исключением, которое бросает Java-машина - при делении на ноль. Но как вызвать исключение самим?</p>
60
<p>Раз исключение - это объект класса, то программисту всего-то и нужно, что создать объект с нужным классом исключения и бросить его с помощью оператора throw.</p>
60
<p>Раз исключение - это объект класса, то программисту всего-то и нужно, что создать объект с нужным классом исключения и бросить его с помощью оператора throw.</p>
61
public static void main(String[] args) { hereWillBeTrouble(42, 0); } private static void hereWillBeTrouble(int a, int b) { if (b == 0) { throw new ArithmeticException("ты опять делишь на ноль?"); } int oops = a / b; System.out.println(oops); }<p>При создании большинства исключений первым параметром в конструктор можно передать сообщение - мы как раз сделали так выше.</p>
61
public static void main(String[] args) { hereWillBeTrouble(42, 0); } private static void hereWillBeTrouble(int a, int b) { if (b == 0) { throw new ArithmeticException("ты опять делишь на ноль?"); } int oops = a / b; System.out.println(oops); }<p>При создании большинства исключений первым параметром в конструктор можно передать сообщение - мы как раз сделали так выше.</p>
62
<p>А получим мы то же самое, что и в самом первом примере, только вместо стандартной фразы "/by zero" теперь выдаётся наш вопрос-пояснение "ты опять делишь на ноль?":</p>
62
<p>А получим мы то же самое, что и в самом первом примере, только вместо стандартной фразы "/by zero" теперь выдаётся наш вопрос-пояснение "ты опять делишь на ноль?":</p>
63
<p>В <a>следующей</a>статье мы углубимся в иерархию исключений Java, узнаем про их разделение на checked и unchecked, а также о том, что ещё интересного можно с ними делать.</p>
63
<p>В <a>следующей</a>статье мы углубимся в иерархию исключений Java, узнаем про их разделение на checked и unchecked, а также о том, что ещё интересного можно с ними делать.</p>
64
<a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>
64
<a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>