Проверяемые и непроверяемые ошибки
Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 61 из 87.
Вы уже видели, что иерархия exception в Java разделяется на разные ветви. Ключевое различие, которое вам нужно понять, — между checked и непроверяемыми exception. Это влияет на то, как вы должны handle их в своём коде.
Checked exceptions — это исключения, которые компилятор заставляет вас обрабатывать. Они напрямую расширяют Exception (не через RuntimeException). Вы должны либо выполнить для них catch, либо объявить их с помощью throws:
// Необходимо обработать IOException — это проверяемое исключение
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path); // Может выбросить IOException
}
// Или перехватить его
public void readFileSafe(String path) {
try {
FileReader reader = new FileReader(path);
} catch (IOException e) {
System.out.println("File error: " + e.getMessage());
}
}Непроверяемые exceptions расширяют RuntimeException. Компилятор не требует от вас handle их. Обычно они указывают на ошибки программирования, такие как нулевые ссылки или недопустимый доступ к массиву:
// Объявление throws не требуется
public int divide(int a, int b) {
return a / b; // Может выбросить ArithmeticException (непроверяемое)
}
String name = null;
name.length(); // NullPointerException (непроверяемое)При создании пользовательских exceptions выбирайте родительский class в зависимости от того, как вы хотите, чтобы вызывающие стороны их обрабатывали. Используйте checked exceptions для восстанавливаемых условий, которые вызывающая сторона должна предусмотреть. Используйте непроверяемые исключения для ошибок программирования, которые не должны возникать в корректном коде.
Задание
ЛегкоДавайте создадим систему проверки возраста, которая демонстрирует ключевое различие между проверяемыми checked и непроверяемыми exception! Вы создадите пользовательские exception обоих типов и увидите, как compiler обрабатывает их по-разному.
Вы организуете свой код в четырёх файлах:
InvalidAgeException.java: Create проверяемое checked exception для сбоев проверки возраста. Это exception должно напрямую расширятьException, а это означает, что Callers будут FORCED его handle. Включите constructor, который accepts message и передаёт его parent class.NegativeAgeException.java: Create непроверяемое exception для случая, когда кто-то указывает отрицательный возраст (ошибка программирования, которой не должно происходить при корректном вводе). Это должно расширятьRuntimeException. Включите constructor, который accepts и передаёт message parent.AgeVerifier.java: Create class, который проверяет возраст с использованием обоих типов exception. Включите два static метода:verifyAge(int age)— этот метод должен выброситьNegativeAgeException(непроверяемое) с message"Age cannot be negative: [age]", если возраст меньше 0. Если возраст меньше 18, выброситеInvalidAgeException(проверяемое) с message"Must be 18 or older: [age]". В противном случае выведитеAge [age] verified successfully. Поскольку этот метод выбрасывает проверяемое exception, вы должны declare его с помощьюthrows InvalidAgeException.verifyAgeUncheckedOnly(int age)— этот метод использует только непроверяемые exception. Если возраст отрицательный, выброситеNegativeAgeExceptionс тем же форматом message. Если возраст меньше 18, выброситеIllegalArgumentExceptionс message"Too young: [age]". В противном случае выведитеAge [age] verified (unchecked method). Обратите внимание: этому методу не нужна декларацияthrows!Main.java: Объедините свою систему проверки! Вы получите один входной параметр: возраст (целое число).Сначала выведите
=== Checked Exception Method ===и вызовитеverifyAgeс введённым возрастом. Поскольку этот метод выбрасывает проверяемое exception, вы должны обернуть его в try-catch. ПерехватитеInvalidAgeExceptionи выведитеChecked exception caught: [message]. Также перехватитеNegativeAgeExceptionи выведитеUnchecked exception caught: [message].Затем выведите пустую строку и
=== Unchecked Exception Method ===. ВызовитеverifyAgeUncheckedOnlyс тем же возрастом. Хотя этот метод может выбрасывать exception, Callers не FORCED перехватывать их. Однако всё равно оберните его в try-catch, чтобы корректно handle ошибки. ПерехватитеNegativeAgeExceptionи выведитеRuntime exception caught: [message]. ПерехватитеIllegalArgumentExceptionи выведитеIllegal argument caught: [message].
Вы получите один входной параметр: целое число, представляющее возраст, который нужно проверить.
Обратите внимание на ключевое различие: метод с проверяемым exception требует декларации throws и FORCED Callers handle его, тогда как непроверяемый метод успешно компилируется без обработки exception. Это фундаментальное различие между проверяемыми и непроверяемыми exception в Java!
Попробуйте сами
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int age = scanner.nextInt();
// TODO: Test the checked exception method
// Print: "=== Checked Exception Method ==="
// Вызовите AgeVerifier.verifyAge(age) в try-catch
// - Catch InvalidAgeException: print "Checked exception caught: [message]"
// - Catch NegativeAgeException: print "Unchecked exception caught: [message]"
// TODO: Print a blank line, then "=== Unchecked Exception Method ==="
// Вызовите AgeVerifier.verifyAgeUncheckedOnly(age) в try-catch
// - Catch NegativeAgeException: print "Runtime exception caught: [message]"
// - Catch IllegalArgumentException: print "Illegal argument caught: [message]"
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыКлючевое слово thisМетодыПоля (атрибуты)Метод-конструкторПерегрузка конструкторовИтоги — Простой калькулятор4Наследование
Основы наследования (extends)Ключевое слово superПереопределение методов (@Override)Цепочка конструкторовКласс ObjectОдиночное и многоуровневое наследованиеПочему нет множественного наследования классовИтоги — Иерархия сотрудников7Специальные методы и класс Object
Метод toString()equals() и hashCode()Метод clone()compareTo() и ComparableИнтерфейс ComparatorПовторение — Кастомная сортировка10Обработка исключений в ООП
Иерархия классов исключенийПользовательские исключенияПроверяемые и непроверяемые ошибкиПаттерн Try With ResourcesПовторение — Validated User2Модификаторы доступа и инкапсуляция
Обзор уровней доступаМетоды геттеры и сеттерыСокрытие данныхКлючевое слово finalИтоги — Менеджер банковского счета5Полиморфизм
Основы перегрузки методовПереопределение методов (Run-Time)Upcasting и DowncastingОператор instanceofАбстрактные классы и методыИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияАгрегация против композицииВнутренние, вложенные и анонимные классыEnums и методы перечисленийRecords (Java 16+)Sealed-классы (Java 17+)11Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн BuilderПаттерн ObserverПаттерн Strategy3Свойства класса и статические члены
Переменные экземпляра и статические переменныеСтатические методыСтатические блокиКонстанты (static final)Итоги: Счетчик и утилиты6Интерфейсы и абстрактные классы
Введение в интерфейсыРеализация интерфейсовРеализация нескольких интерфейсовDefault и Static методы в интерфейсахАбстрактные классы vs ИнтерфейсыФункциональные интерфейсыИтоги — Платежная система9Обобщения
Введение в обобщенияОбобщенные классыОбобщенные методыОграниченные параметры типаСимволы подстановки (Wildcards: ?, extends, super)Итоги — Обобщенный контейнер12Паттерны проектирования. Часть 2
Паттерн «Команда»Паттерн «Адаптер»Паттерн «Декоратор»Паттерн «Шаблонный метод»Паттерн «Состояние»Паттерн «Компоновщик»Паттерн «Итератор»Потренируйтесь самостоятельно: Онлайн-компилятор Java