Throws ioexception в java что это
Правильное использование исключений в Java
Доброго времени суток, уважаемый Хабр.
Я хотел бы рассказать, как правильно нужно использовать исключения в Java. Частично этот материал рассматривается на просторах интернета, а также рассматривается немного в книге J.Bloch Effective Java. Речь пойдет о использовании проверенных и непроверенных (checked/unchecked) исключениях. Статья будет полезна новичкам, т.к. вначале не всегда ясно, как правильно нужно пользоваться исключениями.
Иерархия исключений в Java представлена следующим образом: родительский класс для всех Throwable. От него унаследовано 2 класса: Exception и Error. От класса Exception унаследован еще RuntimeException.
Error – критические ошибки, который могут возникнуть в системе (например, StackOverflowError ). Как правило обрабатывает их система. Если они возникают, то приложение закрывается, так как при данной ситуации работа не может быть продолжена.
Exception – это проверенные исключения. Это значит, что если метод бросает исключение, которое унаследовано от Exception (напр. IOException), то этот метод должен быть обязательно заключен в блок try-catch. Сам метод, который бросает исключение, должен в сигнатуре содержать конструкцию throws. Проверенные (checked) исключения означают, что исключение можно было предвидеть и, соответственно, оно должно быть обработано, работа приложения должна быть продолжена. Пример такого исключения — это попытка создать новый файл, который уже существует (IOException). В данному случае, работа приложения должна быть продолжена и пользователь должен получить уведомление, по какой причине файл не может быть создан.
Например:
В данном примере можно увидеть, что метод createTempFile может выбрасывать IOException, когда файл не может быть создан. И это исключение должно быть обработано соответственно. Если попытаться вызвать этот метод вне блока try-catch, то компилятор выдаст ошибку и будет предложено 2 варианта исправления: окружить метод блоком try-catch или метод, внутри которого вызывается File.createTempFile, должен выбрасывать исключение IOException (чтобы передать его на верхний уровень для обработки).
RuntimeException – это непроверенные исключения. Они возникают во время выполнения приложения. К таким исключениям относится, например, NullPointerException. Они не требуют обязательного заключения в блок try-catch. Когда RuntimeException возникает, это свидетельствует о ошибке, допущенной программистом (неинициализированный объект, выход за пределы массива и т.д.). Поэтому данное исключение не нужно обрабатывать, а нужно исправлять ошибку в коде, чтобы исключение вновь не возникало.
Ниже приведен пример, как правильно работать с RuntimeException:
В данном примере метод принимает объект класса Rectangle. В описании метода содержится строка @throws, которая описывает исключение, которое может быть выброшено и при каких условиях. Однако, сигнатура метода не содержит конструкции throws. Это значит, что при вызове метода его не нужно оборачивать блоком try-catch. А программист должен не допустить передачи в метод неинициализированного объекта.
Надеюсь, такие небольшие разъяснения могут немного разобраться, когда же нужно обрабатывать исключения, а когда нужно просто исправлять ошибки в коде.
Исключения в Java
Обработка исключительных ситуаций (exception handling) — механизм языков программирования, предназначенный для описания реакции программы на ошибки времени выполнения и другие возможные проблемы (исключения), которые могут возникнуть при выполнении программы и приводят к невозможности (бессмысленности) дальнейшей отработки программой её базового алгоритма.
Синтаксис
Здесь в методе getAreaValue мы бросаем исключение IllegalArgumentException с помощью ключевого слова throw. В данном случае в сигнатуре метода отсутствует throws IllegalArgumentException, это не сделано потому что исключение IllegalArgumentException является не проверяемым, о них мы ещё поговорим.
Общий вид конструкции для «поимки» исключительной ситуации выглядит следующим образом:
В нашем случае для площади прямоугольника:
Здесь мы поймали IllegalArgumentException и залогировали данное событие. Дело в том что «починить» такую поломку мы не можем, не будем же мы угадывать что хотел пользователь :). По этому мы пробрасываем данное исключение дальше с помощью «throw e;». Такое часто можно встретить на серверах приложений(веб-серверах).
finally
Иногда требуется гарантировать, что определенный участок кода будет выполняться независимо от того, какие исключения были возбуждены и перехвачены. Для создания такого участка кода используется ключевое слово finally. Даже в тех случаях, когда в методе нет соответствующего возбужденному исключению раздела catch, блок finally будет выполнен до того, как управление перейдет к операторам, следующим за разделом try. У каждого раздела try должен быть по крайней мере или один раздел catch или блок finally. Блок finally очень удобен для закрытия файлов и освобождения любых других ресурсов, захваченных для временного использования в начале выполнения метода. Ниже приведен пример класса с двумя методами, завершение которых происходит по разным причинам, но в обоих перед выходом выполняется код раздела finally.
В этом примере в методе procA из-за возбуждения исключения происходит преждевременный выход из блока try, но по пути «наружу» выполняется раздел finally. Другой метод procB завершает работу выполнением стоящего в try-блоке оператора return, но и при этом перед выходом из метода выполняется программный код блока finally. Ниже приведен результат, полученный при выполнении этой программы.
Иерархия исключений
Все классы обрабатывающие ошибки являются наследниками класса java.lang.Throwable. Только объекты этого класса или его наследников могут быть «брошены» JVM при возникновении какой-нибудь исключительной ситуации, а также только эти объекты могут быть «брошены» во время выполнения программы с помощью ключевого слова throw.
Прямыми наследниками класса Throwable являются Error и Exception.
При программировании на Java основное внимание следует уделять иерархии Exception. Эта иерархия также разделяется на две ветви: исключения, производные от класса RuntimeException, и остальные. Исключения типа RuntimeException возникают вследствие ошибок программирования. Все другие исключения являются следствием непредвиденного стечения обстоятельств, например, ошибок ввода-вывода, возникающих при выполнении вполне корректных программ.
Рассмотрим основные классы исключений.
Создание своих классов исключений
Хотя встроенные исключения Java обрабатывают большинство частых ошибок, вероятно, вам потребуется создать ваши собственные типы исключений для обработки ситуаций, специфичных для ваших приложений. Это достаточно просто сделать: просто определите подкласс Exception (который, разумеется, является подклассом Throwable). Ваши подклассы не обязаны реализовывать что-либо — важно само их присутствие в системе типов, которое позволит использовать их как исключения.
Обработка нескольких исключений
Одному блоку try может соответствовать сразу несколько блоков catch с разными классами исключений.
Это удобно, если обработка ошибок не отличается.
Конструкция try-with-resources
Наследование методов бросающих исключения
Можно лишь сужать класс исключения:
Как бросить проверяемое исключение не обрабатывая его (хак)
Нет ничего невозможного. С помощью рефлексии и внутреннего API языка java можно творить магию :).
В примере используется рефлексия для получения объекта Unsafe так как другими средствами это сделать проблематично. У класса Unsafe приватный конструктор. А если попытаться вызвать статический метод getUnsafe() то будет брошено исключение SecurityException.
Заключение
Изначально я хотел сделать себе шпаргалку по иерархии классов исключений и не планировал писать статью. Но получилось так, что шпаргалка выросла в статью 🙂
Надеюсь она поможет кому-нибудь перед собеседованием, или просто вспомнить/углубить знания 🙂 Спасибо за внимание!
Если Вам понравилась статья, проголосуйте за нее
Голосов: 86 Голосовать
Обработка исключений в Java
Изучите основы обработки исключений в Java, а также некоторые лучшие и худшие практики.
1. Обзор
В этом уроке мы рассмотрим основы обработки исключений в Java, а также некоторые из его ошибок.
2. Основные принципы
2.1. Что Это Такое?
Чтобы лучше понять исключения и обработку исключений, давайте проведем сравнение в реальной жизни.
Представьте, что мы заказываем товар онлайн, но в пути происходит сбой в доставке. Хорошая компания может справиться с этой проблемой и изящно перенаправить наш пакет, чтобы он все равно прибыл вовремя.
Аналогично, в Java код может испытывать ошибки при выполнении наших инструкций. Хорошая обработка исключений может обрабатывать ошибки и изящно перенаправлять программу, чтобы дать пользователю все еще положительный опыт .
2.2. Зачем Его Использовать?
Обычно мы пишем код в идеализированной среде: файловая система всегда содержит ваши файлы, сеть исправна, а у JVM всегда достаточно памяти. Иногда мы называем это “счастливым путем”.
Однако в производственной среде файловые системы могут быть повреждены, сети могут выйти из строя, а JVM могут исчерпать память. Благополучие нашего кода зависит от того, как он справляется с “несчастливыми путями”.
Мы должны обрабатывать эти условия, потому что они негативно влияют на поток приложения и формируют исключения :
Но что может произойти в производстве, если players.dat отсутствует?
Без обработки этого исключения в противном случае работоспособная программа может вообще перестать работать! Мы должны убедиться, что в нашем коде есть план на случай, если что-то пойдет не так.
Также обратите внимание на еще одно преимущество исключений, а именно на саму трассировку стека. Из-за этой трассировки стека мы часто можем точно определить нарушающий код без необходимости подключения отладчика.
3. Иерархия исключений
В конечном счете, исключения – это просто объекты Java, и все они простираются от Throwable :
Существует три основные категории исключительных условий:
Время выполнения и непроверенные исключения относятся к одному и тому же. Мы часто можем использовать их взаимозаменяемо.
3.1. Проверенные Исключения
Проверенные исключения-это исключения, которые компилятор Java требует от нас обрабатывать. Мы должны либо декларативно выбрасывать исключение в стек вызовов, либо обрабатывать его самостоятельно. Подробнее об этом через минуту.
Документация Oracle говорит нам использовать проверенные исключения, когда мы можем разумно ожидать, что вызывающий наш метод сможет восстановиться.
Несколько примеров проверенных исключений: Исключение IOException и ServletException.
3.2. Непроверенные исключения
Непроверенные исключения-это исключения, которые компилятор Java не требует от нас обработки.
И хотя это звучит удобно, документация Oracle говорит нам, что для обеих концепций есть веские причины, например, различать ситуационную ошибку (проверено) и ошибку использования (не проверено).
3.3. Ошибки
Ошибки представляют собой серьезные и обычно невосполнимые условия, такие как несовместимость библиотек, бесконечная рекурсия или утечки памяти.
4. Обработка исключений
В Java API есть много мест, где все может пойти не так, и некоторые из этих мест отмечены исключениями, либо в подписи, либо в Javadoc:
Как было сказано чуть ранее, когда мы называем эти “рискованные” методы, мы должны обрабатывать проверенные исключения, и мы можем обрабатывать непроверенные. Java дает нам несколько способов сделать это:
4.1. бросает
Самый простой способ “обработать” исключение-это выбросить его:
Поскольку FileNotFoundException является проверяемым исключением, это самый простой способ удовлетворить компилятор, но это означает, что любой, кто вызывает наш метод, теперь тоже должен его обрабатывать!
4.2. попробуй-поймай
Или путем выполнения шагов восстановления:
4.3. наконец
В наших примерах до сих пор была неприятная ошибка, скрывающаяся в тени, которая заключается в том, что Java по умолчанию не возвращает дескрипторы файлов в операционную систему.
Конечно, независимо от того, можем ли мы прочитать файл или нет, мы хотим убедиться, что выполнили соответствующую очистку!
Давайте сначала попробуем “ленивый” способ:
Здесь блок finally указывает, какой код мы хотим запустить на Java, независимо от того, что происходит при попытке прочитать файл.
Мы также можем обработать исключение и убедиться, что наши ресурсы будут закрыты:
Потому что закрывать это также “рискованный” метод, нам также нужно поймать его исключение!
Это может показаться довольно сложным, но нам нужна каждая деталь, чтобы правильно справиться с каждой потенциальной проблемой, которая может возникнуть.
4.4. попробуйте с помощью ресурсов
К счастью, начиная с Java 7, мы можем упростить приведенный выше синтаксис при работе с вещами, которые расширяют автоклавируемый :
Тем не менее, мы все еще можем использовать блок finally для любой другой очистки, которую мы хотим.
Ознакомьтесь с нашей статьей, посвященной попыткам с ресурсами, чтобы узнать больше.
4.5. Несколько блоков улавливания
Иногда код может выдавать более одного исключения, и у нас может быть более одного catch блока обработки каждого в отдельности:
Несколько ловушек дают нам возможность обрабатывать каждое исключение по-разному, если возникнет необходимость.
Предположим, однако, что нам нужно рассматривать FileNotFoundException иначе, чем более общее IOException :
Java позволяет нам обрабатывать исключения подклассов отдельно, не забудьте поместить их выше в списке уловов.
4.6. Объединение блоков улова
Однако, когда мы знаем, что способ обработки ошибок будет таким же, Java 7 представила возможность улавливать несколько исключений в одном блоке:
5. Выбрасывание Исключений
Допустим, у нас есть следующее проверенное исключение, которое мы создали сами:
и у нас есть метод, который потенциально может занять много времени для завершения:
5.1. Выбрасывание проверенного исключения
Как и при возврате из метода, мы можем бросить в любой момент.
Конечно, мы должны бросать, когда пытаемся указать, что что-то пошло не так:
Поскольку TimeoutException проверено, мы также должны использовать ключевое слово throws в подписи, чтобы вызывающие наш метод знали, как его обрабатывать.
5.2. Создание непроверенного исключения
Если мы хотим сделать что-то вроде, скажем, проверки ввода, мы можем вместо этого использовать непроверенное исключение:
Поскольку IllegalArgumentException не установлен, нам не нужно отмечать метод, хотя мы можем это сделать.
Некоторые все равно отмечают этот метод как форму документации.
5.3. Упаковка и Переоснащение
Мы также можем выбрать исключение, которое мы поймали:
Или сделайте обертку и перекрасьте:
Это может быть полезно для объединения множества различных исключений в одно.
5.4. Повторное выбрасывание или исключение
Теперь об особом случае.
Если единственными возможными исключениями, которые может вызвать данный блок кода, являются непроверенные исключения, то мы можем перехватить и перестроить Throwable или Исключение без добавления их в сигнатуру нашего метода:
5.5. Наследование
В том случае, когда наш метод вызывает проверенное исключение:
Подкласс может иметь “менее рискованную” подпись:
Но не ” более более рискованная” подпись:
Это связано с тем, что контракты определяются во время компиляции ссылочным типом. Если я создам экземпляр Больше исключений и сохраню его в Исключения :
6. Анти-паттерны
6.1. Глотательные исключения
Теперь есть еще один способ, которым мы могли бы удовлетворить компилятор:
Бывают случаи, когда есть проверенное исключение, которое, как мы уверены, просто никогда не произойдет. В этих случаях мы все равно должны, по крайней мере, добавить комментарий, в котором говорится, что мы намеренно съели исключение :
Еще один способ “проглотить” исключение-просто распечатать исключение из потока ошибок:
Мы немного улучшили нашу ситуацию, по крайней мере, записав ошибку где-нибудь для последующего диагноза.
Однако было бы лучше, если бы мы использовали регистратор:
Хотя нам очень удобно обрабатывать исключения таким образом, нам нужно убедиться, что мы не проглатываем важную информацию, которую вызывающие пользователи нашего кода могли бы использовать для устранения проблемы.
Наконец, мы можем непреднамеренно проглотить исключение, не включив его в качестве причины при создании нового исключения:
Здесь мы похлопываем себя по спине за то, что предупредили нашего вызывающего абонента об ошибке, но мы не включаем IOException в качестве причины. Из-за этого мы потеряли важную информацию, которую абоненты или операторы могли бы использовать для диагностики проблемы.
Нам было бы лучше сделать:
Обратите внимание на тонкую разницу между включением IOException как причина |//CoreException .
6.2. Использование возврата в блоке finally
В соответствии со спецификацией языка Java :
Если блок finally завершается нормально, то оператор try завершается внезапно по причине R.
Если блок finally внезапно завершается по причине S, то оператор try завершается внезапно по причине S (и причина R отбрасывается).
6.3. Использование броска в блоке finally
6.4. Использование броска в качестве гото
Некоторые люди также поддались искушению использовать throw в качестве goto заявления:
Это странно, потому что код пытается использовать исключения для управления потоком, а не для обработки ошибок.
7. Распространенные исключения и ошибки
Вот некоторые распространенные исключения и ошибки, с которыми мы все время сталкиваемся:
7.1. Проверенные исключения
7.2. Исключения во время выполнения
7.3. Ошибки
8. Заключение
В этой статье мы рассмотрели основы обработки исключений, а также некоторые хорошие и плохие примеры практики.
Полное руководство по обработке исключений в Java
Исключение — ошибка, которая нарушает нормальную работу программы. Java обеспечивает надежный объектно-ориентированный способ обработки исключений. Именно его мы и будем изучать в этом руководстве.
Обработка исключений в Java. Краткий обзор
Исключение может возникнуть в разного рода ситуациях: неправильные входные данные, аппаратный сбой, сбоя сетевого соединения, ошибка при работе с базой данных и т.д. Именно поэтому любой Java программист должен уметь правильно обрабатывать исключения, понимать причины их появления и следовать лучшим практикам работы с исключениями даже в небольших проектах.
Java — объектно-ориентированный язык программирования, поэтому всякий раз, когда происходит ошибка при выполнении инструкции, создается объект-исключение, а затем нормальный ход выполнения программы останавливается и JRE пытается найти кого-то, кто может справиться (обработать) это исключение. Объект-исключение содержит много информации об отладке, а именно номер строки, где произошло исключение, тип исключения и т.д.
Что и как происходит, когда появляется ошибка
Когда в методе происходит исключение, то процесс создания объекта-исключения и передачи его в Runtime Environment называется «бросать исключение».
После создания исключения, Java Runtime Environment пытается найти обработчик исключения.
Обработчик исключения — блок кода, который может обрабатывать объект-исключение.
Логика нахождения обработчика исключений проста — прежде всего начинается поиск в методе, где возникла ошибка, если соответствующий обработчик не найден, то происходит переход к тому методу, который вызывает этот метод и так далее.
Если соответствующий обработчик исключений будет найден, то объект-исключение передаётся обработчику.
Обработать исключение — значит «поймать исключение».
Если обработчик исключений не был найден, то программа завершает работу и печатает информации об исключении.
Обратите внимание, что обработка исключений в Java — это фреймворк, который используется только для обработки ошибок времени выполнения. Ошибки компиляции не обрабатываются рамках обработки исключений.
Основные элементы обработки исключений в Java
Мы используем определенные ключевые слова в для создания блока обработки исключений. Давайте рассмотрим их на примере. Также мы напишем простую программу для обработки исключений.
Давайте посмотрим простую программу обработки исключений в Java.
А в консоле эта программа напишет такое:
Важные моменты в обработке исключений:
Иерархия исключений в Java
На рисунке 1 представлена иерархия исключений в Java:
Рисунок 1 — Иерархия исключений в Java
Полезные методы в обработке исключений
Полезные методы класса Throwable :
Автоматическое управление ресурсами и улучшения блока перехвата ошибок в Java 7
Исключения в Java, Часть II (checked/unchecked)
Это вторая часть статьи (первая часть — try-catch-finally), посвященной такому языковому механизму Java как исключения. Она имеет вводный характер и рассчитана на начинающих разработчиков или тех, кто только приступает к изучению языка.
Также я веду курс «Scala for Java Developers» на платформе для онлайн-образования udemy.com (аналог Coursera/EdX).
1. «Магия» checked/unchecked
Механизм исключительных ситуация в Java связан с двумя элементами «магии», т.е. поведения, которое никак не отражено в исходном коде:
1. «Магию» java.lang.Throwable — в throw, catch и throws могут стоять исключительно Throwable или его наследники (мы уже разбирали в предыдущей лекции). Это «право» находиться в throw, catch и throws никак не отражено в исходном коде.
2. Все исключительные ситуации делятся на «проверяемые» (checked) и «непроверяемые» (unchecked). Это свойство присуще «корневищу» (Throwable, Error, Exception, RuntimeException) и передается по наследству. Никак не видимо в исходном коде класса исключения.
В дальнейших примера просто учтите, что
— Throwable и Exception и все их наследники (за исключением наследников Error-а и RuntimeException-а) — checked
— Error и RuntimeException и все их наследники — unchecked
checked exception = проверяемое исключение, проверяемое компилятором.
Что именно проверяет компилятор мы разберем на этой лекции.
Напомним иерархию исключений
Расставим значение свойства checked/unchecked
2. Пессимистичный механизм
Я называю связь между проверяемыми исключениями и throws — «пессимистичной», польку мы можем «напугать» о большем, чем может произойти на самом деле, но не наоборот
Мы не можем бросать, но не предупредить
Мы не можем бросать, но предупредить о «меньшем»
Мы можем предупредить точно о том, что бросаем
Мы можем предупредить о большем, чем мы бросаем
Можем даже предупредить о том, чего вообще нет
Даже если предупреждаем о том, чего нет — все обязаны бояться
Хотя они (испугавшиеся) могут перепугать остальных еще больше
В чем цель «пессимистичности»? Все достаточно просто.
Вы в режиме протипирования «набросали», скажем, класс-утилиту для скачивания из интернета
и хотели бы «принудить» пользователей вашего класса УЖЕ ОБРАБАТЫВАТЬ возможное исключение IOException, хотя из реализации-пустышки вы ПОКА НЕ ГЕНЕРИРУЕТЕ такое исключение. Но в будущем — собираетесь.
3. throws с непроверяемым (unckecked) исключением
Вызов метода, который «пугает» unchecked исключением не накладывает на нас никаких обязанностей.
Эта конструкция служит цели «указать» программисту-читателю кода на то, что ваш метод может выбросить некоторое непроверяемое (unchecked) исключение.
Пример (java.lang.NumberFormatException — непроверяемое исключение):
Integer.parseInt() может бросить unchecked NumberFormatException на неподходящем аргументе (int k = Integer.parseInt(«123abc»)), это отразили
— в сигнатуре метода: throws NumberFormatException
— в документации (javadoc): @ exception
но это ни к чему нас не обязывает.
4. Множественные исключения
Рассмотрим ситуацию с кодом, который может бросать проверяемые исключения разных типов.
Далее учитывайте, что EOFException и FileNotFoundException — потомки IOException.
Мы можем точно указать, что выбрасываем
А можем «испугать» сильнее (предком обоих исключений)
Можно и вот так: EOFException и FileNotFoundException «обобщаем до» IOException, а InterruptedException «пропускаем нетронутым» (InterruptedException — НЕ потомок IOException)
5. Или catch, или throws
Не надо пугать тем, что вы перехватили
так
или так (ставим catch по предку и точно перехватываем)
Но если перехватили только потомка, то не выйдет
Не годится, естественно, и перехватывание «брата»
Если вы часть перехватили, то можете этим не пугать
6. Поведение компилятора/JVM
Необходимо понимать, что
— проверка на cheched исключения происходит в момент компиляции (compile-time checking)
— перехват исключений (catch) происходит в момент выполнения (runtime checking)
Хотя ССЫЛКА ref УКАЗЫВАЕТ на объект типа java.lang.String (у которого имеется метод charAt(int)), но ТИП ССЫЛКИ — java.lang.Object (ссылка типа java.lang.Object на объект типа java.lang.String). Компилятор ориентируется на «левый тип» (тип ссылки, а не тип ссылаемого) и не пропускает такой код.
Хотя В ДАННОЙ СИТУАЦИИ компилятор мог бы разобрать, что t ссылается на Exception, а ref — на String, но этого уже невозможно сделать при раздельно компиляции. Представьте, что мы МОГЛИ БЫ скомпилировать ОТДЕЛЬНО такой класс, упаковать в jar и распространять
А кто-то берет этот класс, добавляет в classpath и вызывает App.f0(new Throwable()) или App.f1(new Integer(42)). В таком случае JVM столкнулась бы с ситуацией, когда от нее требует бросить проверяемое исключение, которое не отследил компилятор (в случае с f0) или вызвать метод, которого нет (в случае с f1)!
Компилятор не пропустит этот код, хотя метод main ГАРАНТИРОВАННО НЕ ВЫБРОСИТ ИСКЛЮЧЕНИЯ
7. Overriding и throws
При переопределении (overriding) список исключений потомка не обязан совпадать с таковым у предка.
Но он должен быть «не сильнее» списка предка:
Однако тут мы попытались «расширить тип» бросаемых исключений
Почему можно сужать тип, но не расширять?
Рассмотрим следующую ситуацию:
Внимательно посмотрите на этот пример — если бы потомок мог расширять тип бросаемого исключения предка, то те места которые «ждут» предка, а получают экземпляр «расширенного» потомка могли бы неконтролируемо выбрасывать проверяемые исключения
8. Передача свойства по наследству
Напомним иерархию исключений с расставленными флагами свойства checked/unchecked
Логика расположения свойства НЕ СВЯЗАНА С НАСЛЕДОВАНИЕМ. Эту логику мы рассмотрим позже (в следующих статьях).
Однако свойство checked/unchecked пользовательских классов исключений строится ИСКЛЮЧИТЕЛЬНО НА ОСНОВЕ НАСЛЕДОВАНИЯ.
Правило крайне простое:
1. Если исключение из списка Throwable, Error, Exception, RuntimeException — то твое свойство надо просто запомнить.
2. Если ты не из списка, то твое свойство равно свойству предка. Нарушить наследование тут нельзя.
Если мы породим потомков A, B, C, D, E, F, G, H, I, J, K, L которые следующим образом наследуются от «корневища» (Throwable, Error, Exception, RuntimeException), то значение их свойства checked/unchecked можно увидеть на схеме