Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое проверяемые исключения (Checked Exceptions)?
Проверяемые исключения — это исключения, которые компилятор ОБЯЗЫВАЕТ обработать или объявить. Если вы этого не сделаете — код не скомпилируется.
Иерархия исключений в Java
Throwable (корень всех ошибок)
├── Exception (можно обработать)
│ ├── Checked Exception (IOException, SQLException, ...)
│ └── RuntimeException (NullPointerException, IndexOutOfBoundsException, ...)
└── Error (нельзя обработать, критичные ошибки)
├── OutOfMemoryError
├── StackOverflowError
└── VirtualMachineError
Проверяемые — наследники Exception (кроме RuntimeException).
Непроверяемые — RuntimeException и Error.
Примеры проверяемых исключений
import java.io.*;
// IOException — проверяемое
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path); // Может выбросить IOException
// ...
}
// SQLException — проверяемое
public User getUserFromDB(int id) throws SQLException {
// SELECT * FROM users WHERE id = ?
// Может выбросить SQLException
return null;
}
// ParseException — проверяемое
public LocalDate parseDate(String date) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
return format.parse(date); // Может выбросить ParseException
}
Обязательная обработка
Вариант 1: Try-Catch (обработка)
public void processFile(String path) {
try {
FileReader reader = new FileReader(path);
// Код обработки файла
} catch (FileNotFoundException e) {
System.err.println("Файл не найден: " + e.getMessage());
} catch (IOException e) {
System.err.println("Ошибка чтения: " + e.getMessage());
}
}
Вариант 2: Throws (переброска)
// Говорим компилятору: "Я не буду это обрабатывать, пусть вызывающий код справляется"
public void processFile(String path) throws IOException {
FileReader reader = new FileReader(path); // IOException выбросится наверх
}
// Тогда вызывающий код ДОЛЖЕН обработать
public void runApplication() throws IOException {
processFile("data.txt"); // Или try-catch
}
Разница: Checked vs Unchecked
// ✅ Checked Exception — ОБЯЗАТЕЛЬНО обработать
try {
Thread.sleep(1000); // InterruptedException — checked
} catch (InterruptedException e) {
e.printStackTrace();
}
// ❌ Непроверяемое исключение — опционально обработать
try {
int[] arr = new int[5];
int x = arr[10]; // ArrayIndexOutOfBoundsException — unchecked
} catch (ArrayIndexOutOfBoundsException e) {
// Это необязательно, но можно
e.printStackTrace();
}
Когда вы NOT обработаете checked exception
// ❌ ОШИБКА КОМПИЛЯЦИИ
public void badMethod() {
FileReader reader = new FileReader("file.txt"); // FileNotFoundException extends IOException
// Компилятор скажет:
// "Unhandled exception: java.io.IOException"
}
// ✅ ПРАВИЛЬНО (вариант 1)
public void goodMethod1() throws IOException {
FileReader reader = new FileReader("file.txt");
}
// ✅ ПРАВИЛЬНО (вариант 2)
public void goodMethod2() {
try {
FileReader reader = new FileReader("file.txt");
} catch (IOException e) {
// Обработка
}
}
Практический пример: работа с БД
public class UserRepository {
// Вариант 1: throws (переброска)
public User findById(int id) throws SQLException {
String sql = "SELECT * FROM users WHERE id = ?";
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/db");
// Может выбросить SQLException
return null;
}
// Вариант 2: try-catch (обработка)
public User findByIdSafe(int id) {
try {
String sql = "SELECT * FROM users WHERE id = ?";
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/db");
// SELECT, обработка результата
return null;
} catch (SQLException e) {
System.err.println("Database error: " + e.getMessage());
return null; // Или выбросить custom exception
}
}
}
// Вызывающий код ДОЛЖЕН обработать
public class UserService {
private final UserRepository repo;
public void processUser(int userId) throws SQLException {
User user = repo.findById(userId); // throws SQLException
// ...
}
}
Полезный паттерн: Try-with-resources
Для автоматического закрытия ресурсов:
// ✅ Современный способ (Java 7+)
public void readFile(String path) throws IOException {
try (FileReader reader = new FileReader(path); // Автоматически закроется
BufferedReader buffered = new BufferedReader(reader)) {
String line;
while ((line = buffered.readLine()) != null) {
System.out.println(line);
}
} // FileReader и BufferedReader закроются автоматически
}
// ❌ Старый способ (до Java 7)
public void readFileOld(String path) throws IOException {
FileReader reader = null;
try {
reader = new FileReader(path);
// обработка
} finally {
if (reader != null) {
reader.close(); // Нужно закрывать вручную
}
}
}
Контроверсия: Полезны ли проверяемые исключения?
За (классический Java подход): ✓ Явная сигнализация об ошибках ✓ Разработчик ДОЛЖЕН подумать об ошибках ✓ Безопасность
Против (современный подход): ✗ Много boilerplate кода ✗ Переброска throws растёт вверх по стеку ✗ Часто просто ловят и игнорируют ✗ Java 8+ потоки не поддерживают throws
// Проблема с потоками
List<String> files = Arrays.asList("file1.txt", "file2.txt");
// ❌ Не компилируется!
files.forEach(file -> readFile(file)); // readFile throws IOException
// ✅ Нужно обернуть в try-catch
files.forEach(file -> {
try {
readFile(file);
} catch (IOException e) {
e.printStackTrace();
}
});
Best Practice в современном Java
// ✅ Оборачивать checked в unchecked
public User findUserById(int id) { // Без throws!
try {
// Database call
return getUserFromDB(id); // throws SQLException
} catch (SQLException e) {
throw new RuntimeException("Database error", e); // Wrap in unchecked
}
}
// Тогда вызывающий код не обязан обрабатывать
User user = findUserById(123); // No try-catch needed
Вывод
Проверяемые исключения:
- ✅ Заставляют думать об ошибках
- ❌ Добавляют boilerplate
- ⚡ Часто оборачивают в
RuntimeException - 📌 Используются в I/O, SQL, сетевых операциях
Модернизированный Java предпочитает unchecked exceptions, но проверяемые остаются частью стандартной библиотеки.