Throw и throws

Базовый Java
≈ 2 мин чтения

Throw: создать исключительную ситуацию вручную

Исключение не обязательно должно возникнуть само из-за деления на ноль или неверного индекса. Код может явно сообщить, что продолжать обычное выполнение нельзя. Для этого используется оператор throw.

static void validateAge(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("age");
    }

    System.out.println("valid");
}

Выражение new IllegalArgumentException("age") создаёт объект исключения, а throw запускает его как исключительную ситуацию. Если age отрицательный, строка с valid в этом вызове метода уже не выполнится.

После throw обычное выполнение прерывается

Как только выполняется throw, Java прекращает обычное выполнение текущего участка кода и ищет подходящий обработчик. Уже знакомый catch может перехватить выброшенный объект, если его тип подходит обработчику.

try {
    validateAge(-5);
    System.out.println("after call");
} catch (IllegalArgumentException e) {
    System.out.println("caught");
}

System.out.println("done");

Вызов validateAge(-5) приводит к throw, поэтому after call не выводится. Управление переходит в catch, а после него программа продолжает работу и выводит done.

Throws описывает, что исключение может выйти из метода

Ключевое слово throws записывается в объявлении метода после списка параметров. Оно показывает, что исключение указанного типа может покинуть метод и перейти к вызывающему коду.

static void checkAccess(boolean allowed) throws Exception {
    if (!allowed) {
        throw new Exception("denied");
    }
}

Здесь throw выполняется внутри тела метода и действительно выбрасывает объект исключения, а throws Exception находится в сигнатуре и описывает возможность выхода этого исключения наружу. Сам по себе throws ничего не выбрасывает и не обрабатывает.

throw и throws решают разные задачи. throw — это действие внутри кода: выбросить конкретный объект исключения. throws — часть объявления метода: указать тип исключения, которое может выйти из него.

Исключение может пройти через несколько вызовов

Метод не обязан обрабатывать исключение в том же месте, где оно возникло. Если подходящего catch внутри метода нет, исключение может перейти к вызывающему коду, где его уже можно обработать.

static void open() throws Exception {
    checkAccess(false);
}

try {
    open();
} catch (Exception e) {
    System.out.println("caught");
}

В этом примере исключение создаётся и выбрасывается в checkAccess(), проходит через open() и перехватывается внешним catch. Так throw, throws и уже знакомый catch работают вместе: исключение возникает в одном месте, может быть передано выше и обработано там, где это предусмотрено кодом.