Menu
Coddy logo textTech

Проверяемые и непроверяемые ошибки

Часть раздела Объектно-ориентированное программирование путешествия по 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 для восстанавливаемых условий, которые вызывающая сторона должна предусмотреть. Используйте непроверяемые исключения для ошибок программирования, которые не должны возникать в корректном коде.

challenge icon

Задание

Легко

Давайте создадим систему проверки возраста, которая демонстрирует ключевое различие между проверяемыми 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]"
        
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Java