Ответ
Компилятор Java выполняет статическую проверку (compile-time checking) для проверяемых исключений (классы, наследующие Exception, но не RuntimeException).
Правило: Если метод может сгенерировать проверяемое исключение, он должен либо:
- Объявить его в своей сигнатуре с помощью
throws. - Обработать его внутри с помощью блока
try-catch.
Пример 1: Объявление исключения
public void readFile(String path) throws IOException {
// Код, который может вызвать FileNotFoundException (наследник IOException)
Files.readAllLines(Paths.get(path));
}
Пример 2: Обработка исключения
public void readFile(String path) {
try {
Files.readAllLines(Paths.get(path));
} catch (IOException e) { // IOException перехвачено и обработано
System.err.println("Файл не найден: " + e.getMessage());
}
}
Если правило нарушено, компилятор выдаст ошибку:
unreported exception <ExceptionClass>; must be caught or declared to be thrown
Важно: Это правило не применяется к непроверяемым исключениям (RuntimeException, например, NullPointerException) и ошибкам (Error, например, OutOfMemoryError).
Ответ 18+ 🔞
Ну слушай, вот есть у нас в Java эта вся ебля с исключениями. Так вот, компилятор — он как занудный охранник в стрёмной конторе: если ты хочешь выкинуть проверяемое исключение (это те, что наследуются от Exception, но не от RuntimeException), то ты должен либо предупредить всех заранее, либо разобраться с ним на месте, блядь.
Короче, правило такое, ёпта:
Если твой метод может выкинуть проверяемое исключение, то ты либо:
- Объявляешь его в сигнатуре через
throws— типа, "ребята, я тут такое могу устроить, будьте готовы". - Обрабатываешь его сразу через
try-catch— то есть сам всё замял, и никто даже не узнал.
Пример первый: предупреждаем, как честные люди
public void readFile(String path) throws IOException {
// Тут может вылезти FileNotFoundException (а он наследник IOException)
Files.readAllLines(Paths.get(path));
}
Вот смотри: метод говорит — "да, я могу кинуть IOException, потому что файл может быть не найден, например. Кто меня вызывает — тот пусть сам решает, что с этим делать".
Пример второй: сами всё похороним
public void readFile(String path) {
try {
Files.readAllLines(Paths.get(path));
} catch (IOException e) { // Поймали эту гадость и тихо обработали
System.err.println("Файл не найден, ёпта: " + e.getMessage());
}
}
А тут мы сами всё порешали внутри метода. Вызвал кто-то — и даже не узнал, что там что-то пошло не так (ну, кроме сообщения в консоль, конечно).
А если проигнорируешь это правило?
Компилятор тебе сразу: unreported exception <ExceptionClass>; must be caught or declared to be thrown.
Перевод: "Мудак, ты либо поймай это исключение, либо объяви, что ты его кидаешь! Иначе не скомпилирую, иди нахуй".
Важный момент, блядь: это всё не касается непроверяемых исключений (RuntimeException, типа NullPointerException) и ошибок (Error, типа OutOfMemoryError). Их можно кидать как угодно, и компилятор даже бровью не поведёт — потому что они обычно от твоей криворукости или системных проблем, а не от логики работы метода.