Исключения
Для стандартного блока try-catch-finally требуется указания либо (от одного и более) блока catch
, либо блок finally
, либо комбинации блоков.
Для блока try-with-resources данные блоки не обязательны, если метод close
у имплементации не выкидывает исключений:
1 | try(var noExceptionCloseable = new NoExceptionCloseable()) { ... } |
Иерархия
1 | ::::::::::::::::::::::::::::::::::: |
Пользователь должен наследовать ошибки от Exception
. Error
предназначен для тех случаев, когда ошибка свидетельствует о невозможности продолжения работы приложения.
Основные Runtime
исключения:
ArithmeticException
- например, при делении на 0;ArrayIndexOutOfBoundsException
;ClassCastException
;NullPointerException
;IllegalArgumentException
- часто возникает в связи с ограничениями безопасности; или когда Java приложение еще не готово выполнить код;NumberFormatException
- например, при преобразовании строки в число (Integer.parseInt("the number"
));IllegalArgumentException
;MissingResourceException
;NumberFormatException
;NullPointerException
;UnsupportedOperationException
;ArrayStoreException
- попытка сохранения в массив определенного типа, объектов другого типа:
1 | Object[] arr = new String[3]; |
Основные checked исключения:
IOException
;FileNotFoundException
;DataFormatException
;InterruptedException
;ParseException
;SQLException
;
Наиболее часто встречающиеся Error
:
AssertionError
;ExceptionInInitializerError
;StackOverflowError
;NoClassDefFoundError
;
Multi-catch
Перехват исключений в 1 блоке catch
не допускает обработки наследуемых классов исключений (т.е. связанных):
1 | try { |
Компилятор посчитает такой catch
избыточным - достаточно обрабатывать родительский IOException
.
Finally
Если в finally
есть return
и в приложение во время выполнения до него дошло, то метод будет возвращать именно это значение, а не расположеное в блоке try
:
1 | try { |
Правило “последнее слово за finally
“ актуально и для исключений:
1 | try { |
try-with-resources
Ресурсы закрываются при выходе из блока try
, т.е. до catch
и до finally
. Закрытие ресурсов происходит в обратном направлении относительно открытия - т.е. при визуальном просмотре снизу вверх:
1 | try(TestCloseable tc1 = new TestCloseable("tc1"); |
Вывод:
1 | init tc1 -> init tc2 -> try block -> close tc2 -> close tc1 -> finally block |
При try-with-resources создается псевдо-finally
, который всегда закрывается перед указанным finally
, и перед(!) catch
с целевой ошибкой:
try
- hidden finally
catch
finally
Если переменные с ресурсами finally или effective finally, то их можно инициализировать вне finally
:
1 | final FileInputStream fis = ...; |
Suppressed
Метод close
может выкидывать ошибки внутри своей реализации. В этом случае они будут обрабатываться как “обычные” исключения в рамках собственного catch
блока:
1 | try(var closeInternalEx1 = Internal.create(1); |
В примере выше будет выведена только 1 ошибка с 1 suppressed исключением и только (!) для второго (closeInternalEx2
) ресурса, поскольку он будет закрываться первым (и до закрытия 1-го рерсурса (closeInternalEx1
) дело даже не дойдет).
Но если в блоке try
возникнет какая-то ошибка, то перехват исключения будет выполнен уже для него, а в качестве suppressed будет указано уже 2 исключения (на каждый ресурс):
1 | try(var closeInternalEx1 = Internal.create(1); |
Override правила
При перезаписи метода, добавление новых исключений, не описанных в родительской сигнатуре запрещены. Вместе с этим, допускается детализация (указание дочернего) исключения. Так же, снятие исключений с методов допускается:
1 | void method1() {...} |
assert
По умолчанию Java выключает assert
. Включается посредством флага -enableassertions
или -ea
при запуске Java приложения.
В случае если assert нужно включить только для одного пакета или класса, то они указываются после флага и разделяются символом “;”:
1 | java -ea:my.pack.assertions.on RunProgramClass |
Для принудительного отключения можно использовать флаги -disableassertions
или -da
. Так же доступно отключение assert
конкретных пакетов и классов:
1 | java -ea:another.assertions.off RunProgramClass -da:another.assertions.off.CustomClass RunProgramClass |
В примере выше, assert
для пакета another.assertions.off
включены, но только для класса CustomClass
отключены.
Важнейшим правилом при написании assert
является то, что assert
не должен (!) влиять на данные внутри объектов, которых он так или иначе касается.