Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как создать своё исключение

Короткий ответ

Создайте класс, унаследованный от RuntimeException, и передайте сообщение в конструктор родителя:

class InsufficientFundsException extends RuntimeException {
    InsufficientFundsException(String message) {
        super(message);
    }
}
 
void withdraw(int balance, int amount) {
    if (amount > balance) {
        throw new InsufficientFundsException("Need " + amount + ", have " + balance);
    }
}
 
void main() {
    try {
        withdraw(100, 250);
    } catch (InsufficientFundsException e) {
        IO.println("Error: " + e.getMessage());
    }
}

Результат:

Error: Need 250, have 100

Проверяемое или нет

Наследник RuntimeException — непроверяемое исключение: компилятор не требует его обрабатывать. Наследник Exception — проверяемое: метод обязан объявить его в throws, а вызывающий код — обработать:

class ConfigException extends Exception {
    ConfigException(String message) {
        super(message);
    }
}
 
String readSetting(String key) throws ConfigException {
    throw new ConfigException("Missing setting: " + key);
}
 
void main() {
    try {
        readSetting("db.url");
    } catch (ConfigException e) {
        IO.println(e.getMessage());
    }
}

Результат:

Missing setting: db.url

Причина

Если исключение возникло из-за другого, передайте исходное вторым аргументом — оно сохранится в getCause():

class ImportException extends RuntimeException {
    ImportException(String message, Throwable cause) {
        super(message, cause);
    }
}
 
void main() {
    try {
        try {
            Integer.parseInt("12x");
        } catch (NumberFormatException e) {
            throw new ImportException("Bad row 7", e);
        }
    } catch (ImportException e) {
        IO.println(e.getMessage());
        IO.println(e.getCause().getMessage());
    }
}

Результат:

Bad row 7
For input string: "12x"

Дополнительные данные

В исключении можно хранить поля — например, код ошибки для ответа API:

class ApiException extends RuntimeException {
    private final int status;
 
    ApiException(int status, String message) {
        super(message);
        this.status = status;
    }
 
    int status() {
        return status;
    }
}
 
void main() {
    try {
        throw new ApiException(404, "Order not found");
    } catch (ApiException e) {
        IO.println(e.status() + " " + e.getMessage());
    }
}

Результат:

404 Order not found

Частая ошибка

Унаследоваться от Exception, но не объявить исключение в throws. Компилятор отказывается собирать такой код:

class ConfigException extends Exception {
    ConfigException(String message) {
        super(message);
    }
}
 
void load() {
    throw new ConfigException("no file");
}
 
void main() {
    load();
}

Результат:

Main.java:8: error: unreported exception Main.ConfigException; must be caught or declared to be thrown

Функции из этого ответа

  • throw — Бросает исключение и прерывает выполнение метода.
  • throws — Объявляет, какие проверяемые исключения может бросить метод.
  • RuntimeException — Базовый класс непроверяемых исключений — ошибок в логике программы.
  • Throwable.getMessage() — Возвращает текст сообщения исключения.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.