Каким типом являются элементы в Exception: проверяемыми или непроверяемым?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Исключения в Java: проверяемые vs непроверяемые
Исключения (Exceptions) в Java делятся на два типа: проверяемые (checked) и непроверяемые (unchecked). Это фундаментальное понимание необходимо для написания надёжного Java кода.
Иерархия исключений
Throwable
├── Exception
│ ├── Checked Exception (должны обрабатываться или объявляться)
│ │ ├── IOException
│ │ ├── SQLException
│ │ ├── ClassNotFoundException
│ │ └── ... (наследуют Exception, но не RuntimeException)
│ │
│ └── Unchecked Exception (RuntimeException и наследники)
│ ├── RuntimeException
│ │ ├── NullPointerException
│ │ ├── ArrayIndexOutOfBoundsException
│ │ ├── IllegalArgumentException
│ │ ├── IllegalStateException
│ │ └── ...
│
└── Error (не должны ловиться, критичные)
├── OutOfMemoryError
├── StackOverflowError
└── ...
1. Проверяемые исключения (Checked Exceptions)
Проверяемые исключения — это исключения, которые должны быть либо:
- Обработаны (try-catch)
- Объявлены в сигнатуре метода (throws)
// IOException — проверяемое исключение
public class FileReader {
// Способ 1: Обработать исключение
public String readFile(String filePath) {
try {
FileInputStream fis = new FileInputStream(filePath);
// Чтение файла
return content;
} catch (IOException e) {
// Обработка ошибки
System.err.println("Cannot read file: " + e.getMessage());
return null;
}
}
// Способ 2: Объявить в throws
public String readFileThrows(String filePath) throws IOException {
FileInputStream fis = new FileInputStream(filePath);
// Чтение файла
return content;
// IOException распространяется вверх по call stack'у
}
// Способ 3: Обрабатываем и объявляем (редко)
public String readFileHybrid(String filePath) throws IOException {
try {
FileInputStream fis = new FileInputStream(filePath);
return content;
} catch (FileNotFoundException e) {
throw new IOException("File not found: " + filePath, e);
}
}
}
Примеры проверяемых исключений:
IOException— ошибки ввода-выводаSQLException— ошибки БДClassNotFoundException— класс не найденInterruptedException— поток прерванFileNotFoundException— файл не найденParseException— ошибка парсинга
Проверка компилятором:
public void methodWithoutException() {
FileInputStream fis = new FileInputStream("file.txt"); // ОШИБКА!
// Compiler error: Unhandled exception: java.io.FileNotFoundException
// Нужно либо try-catch, либо throws
}
2. Непроверяемые исключения (Unchecked Exceptions)
Непроверяемые исключения — это RuntimeException и его наследники. Компилятор не требует их обработки.
public class UncheckedExceptions {
// Компилятор НЕ требует обработки
public void divideByZero() {
int result = 10 / 0; // ArithmeticException (unchecked)
// Компилятор не ругается
}
// NullPointerException
public void nullPointerExample() {
String str = null;
int length = str.length(); // NullPointerException
// Компилятор не требует обработки
}
// Но можно обрабатывать
public void handleUnchecked() {
try {
Object obj = null;
obj.toString();
} catch (NullPointerException e) {
System.err.println("Null pointer caught: " + e.getMessage());
}
}
}
Примеры непроверяемых исключений:
NullPointerException— null referenceArrayIndexOutOfBoundsException— индекс за границамиClassCastException— неправильный castIllegalArgumentException— неверный аргументNumberFormatException— ошибка формата числаArithmeticException— деление на ноль
Сравнительная таблица
| Аспект | Checked Exception | Unchecked Exception |
|---|---|---|
| Родительский класс | Exception (но не RuntimeException) | RuntimeException |
| Требование обработки | ✓ Да, обязательно | ✗ Нет, опционально |
| Проверка компилятором | ✓ Да | ✗ Нет |
| Примеры | IOException, SQLException | NullPointerException, IllegalArgumentException |
| Когда возникает | В runtime, предсказуемо | В runtime, часто неожиданно |
| Что делать | Обработать или объявить | Предотвратить логикой |
Выбор между checked и unchecked
Когда использовать Checked Exception:
// Ошибки ввода-вывода
public byte[] readFileContent(String path) throws IOException {
return Files.readAllBytes(Paths.get(path));
}
// Ошибки БД
public User getUserFromDatabase(Long id) throws SQLException {
// ...
}
// Network ошибки
public String fetchFromApi(String url) throws IOException {
// ...
}
Правило: Используй checked exception, когда вызывающий код может обоснованно восстановиться от ошибки.
Когда использовать Unchecked Exception:
// Ошибки валидации (код ошибка вызывающего)
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age cannot be negative");
}
this.age = age;
}
// Программные ошибки (нужна мена логики)
public String getString(List<String> list, int index) {
if (index < 0 || index >= list.size()) {
throw new IndexOutOfBoundsException("Invalid index: " + index);
}
return list.get(index);
}
// Null checks
public void processUser(User user) {
if (user == null) {
throw new IllegalArgumentException("User cannot be null");
}
// ...
}
Правило: Используй unchecked exception для программных ошибок, которые вызываются некорректным кодом вызывающего.
Практические примеры
1. Правильная обработка checked exception
public class DataImporter {
public void importDataFromFile(String filePath) {
try {
FileInputStream fis = new FileInputStream(filePath);
BufferedReader reader = new BufferedReader(
new InputStreamReader(fis)
);
String line;
while ((line = reader.readLine()) != null) {
processLine(line);
}
reader.close();
} catch (FileNotFoundException e) {
System.err.println("File not found: " + filePath);
// Можем создать файл или уведомить пользователя
} catch (IOException e) {
System.err.println("Error reading file: " + e.getMessage());
// Retry логика
}
}
private void processLine(String line) {
// Логика обработки
}
}
2. Правильная валидация с unchecked exception
public class User {
private String email;
private int age;
public User(String email, int age) {
if (email == null || email.isEmpty()) {
throw new IllegalArgumentException("Email cannot be empty");
}
if (!email.contains("@")) {
throw new IllegalArgumentException("Email format invalid");
}
if (age < 0 || age > 150) {
throw new IllegalArgumentException("Age must be between 0 and 150");
}
this.email = email;
this.age = age;
}
}
// Использование
public static void main(String[] args) {
try {
User user = new User("john@example.com", 30);
} catch (IllegalArgumentException e) {
System.err.println("Invalid user data: " + e.getMessage());
}
}
3. Обёртывание checked exception
public class DataService {
// Оборачиваем checked exception в unchecked
public List<User> getAllUsers() {
try {
return userRepository.fetchFromDatabase();
} catch (SQLException e) {
// SQLException — checked, но мы не можем восстановиться
throw new DataAccessException("Failed to fetch users", e);
}
}
}
public class DataAccessException extends RuntimeException {
public DataAccessException(String message, Throwable cause) {
super(message, cause);
}
}
Best Practices
1. Не игнорируй исключения
// ПЛОХО: Invisible exception
try {
riskyOperation();
} catch (IOException e) {
// Пустой catch — это ошибка!
}
// ХОРОШО: Логирование или пробрас
try {
riskyOperation();
} catch (IOException e) {
log.error("Operation failed", e);
throw new RuntimeException("Failed to complete operation", e);
}
2. Ловай конкретные исключения
// ПЛОХО: Слишком общее
try {
fileOperation();
} catch (Exception e) {
// Можешь случайно поймать Throwable
}
// ХОРОШО: Конкретное исключение
try {
fileOperation();
} catch (IOException e) {
// Только expected исключения
}
3. Используй try-with-resources
// ПЛОХО: Риск утечки ресурсов
FileInputStream fis = new FileInputStream("file.txt");
try {
// ...
} finally {
fis.close(); // Может не выполниться
}
// ХОРОШО: Автоматическое закрытие
try (FileInputStream fis = new FileInputStream("file.txt")) {
// fis.close() выполнится автоматически
}
Выводы
Проверяемые исключения (Checked):
- ✓ Обязательно обрабатывать
- ✓ Явно объявлять в throws
- ✓ Для ошибок, которые можно восстановить
- ✓ IOException, SQLException, ClassNotFoundException
Непроверяемые исключения (Unchecked):
- ✓ Опционально обрабатывать
- ✓ Не нужно объявлять в throws
- ✓ Для программных ошибок
- ✓ NullPointerException, IllegalArgumentException, ArithmeticException
Правило большого пальца:
- Используй checked exceptions для внешних ошибок (файлы, сеть, БД)
- Используй unchecked exceptions для ошибок логики кода
- Всегда логируй исключения с полным контекстом
- Предпочитай specific exceptions в catch блоках