← Назад к вопросам

Можно ли перехватывать непроверяемые исключения?

1.2 Junior🔥 131 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Можно ли перехватывать непроверяемые исключения?

Да, абсолютно да! Непроверяемые (unchecked) исключения могут и должны перехватываться в try-catch блоках точно так же, как и проверяемые исключения. Разница только в том, что компилятор не требует их обработки.

Типы исключений в Java

1. Проверяемые (Checked) исключения

Компилятор заставляет обрабатывать:

import java.io.FileReader;
import java.io.IOException;

public class CheckedExample {
    public static void main(String[] args) {
        try {
            // IOException — это checked исключение
            // Компилятор ТРЕБУЕТ обработку
            FileReader file = new FileReader("file.txt");
        } catch (IOException e) {
            System.out.println("Ошибка при чтении файла: " + e.getMessage());
        }
    }
}

2. Непроверяемые (Unchecked) исключения

Компилятор не требует обработки, но мы можем перехватить:

public class UncheckedExample {
    public static void main(String[] args) {
        try {
            // NullPointerException — это unchecked исключение
            // Компилятор НЕ требует обработку
            // Но мы можем её сделать
            String text = null;
            System.out.println(text.length());  // Выбросит NPE
        } catch (NullPointerException e) {
            System.out.println("Перехвачено: " + e.getMessage());
        }
    }
}

Иерархия исключений

Throwable
├── Error (ошибки JVM)
│   ├── OutOfMemoryError
│   ├── StackOverflowError
│   └── LinkageError
└── Exception
    ├── IOException (Checked)
    ├── SQLException (Checked)
    ├── RuntimeException (Unchecked) ← ВАЖНО!
    │   ├── NullPointerException
    │   ├── ArrayIndexOutOfBoundsException
    │   ├── IllegalArgumentException
    │   ├── ClassCastException
    │   └── ArithmeticException
    └── ... другие проверяемые

Основные непроверяемые исключения

public class UncheckedExceptionsDemo {
    public static void main(String[] args) {
        
        // 1. NullPointerException
        try {
            String text = null;
            int length = text.length();  // NPE
        } catch (NullPointerException e) {
            System.out.println("1. Перехвачено NPE");
        }
        
        // 2. ArrayIndexOutOfBoundsException
        try {
            int[] arr = {1, 2, 3};
            int value = arr[10];  // Index out of bounds
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("2. Перехвачено AIOOBE");
        }
        
        // 3. ArithmeticException
        try {
            int result = 10 / 0;  // Division by zero
        } catch (ArithmeticException e) {
            System.out.println("3. Перехвачено ArithmeticException");
        }
        
        // 4. ClassCastException
        try {
            Object obj = "строка";
            Integer num = (Integer) obj;  // Invalid cast
        } catch (ClassCastException e) {
            System.out.println("4. Перехвачено ClassCastException");
        }
        
        // 5. IllegalArgumentException
        try {
            Integer.parseInt("abc");  // Не число
        } catch (NumberFormatException e) {  // Подвид IAE
            System.out.println("5. Перехвачено NumberFormatException");
        }
    }
}

Разница между Checked и Unchecked

public class ComparisonExample {
    
    // Checked исключение — компилятор ТРЕБУЕТ обработку
    public void readFile(String filename) throws IOException {
        FileReader file = new FileReader(filename);
    }
    
    // Unchecked исключение — можно НЕ указывать в throws
    // Но это не значит, что его нельзя перехватить!
    public void parseNumber(String input) {
        int num = Integer.parseInt(input);  // Может выбросить NFE
    }
    
    public static void main(String[] args) {
        ComparisonExample example = new ComparisonExample();
        
        // Checked — ДОЛЖЕН обработать
        try {
            example.readFile("data.txt");
        } catch (IOException e) {
            System.out.println("Ошибка IO");
        }
        
        // Unchecked — МОЖЕТ обработать (опционально)
        try {
            example.parseNumber("123");
        } catch (NumberFormatException e) {
            System.out.println("Ошибка формата");
        }
    }
}

Практические сценарии

1. Защита от NullPointerException

public class NullSafeExample {
    public static void processUser(User user) {
        try {
            String name = user.getName();        // Может быть NPE
            String email = user.getEmail();      // Может быть NPE
            System.out.println(name + " : " + email);
        } catch (NullPointerException e) {
            System.out.println("Пользователь null или содержит null поля");
        }
    }
}

2. Валидация входных данных

import java.util.ArrayList;
import java.util.List;

public class ValidationExample {
    public static void main(String[] args) {
        try {
            // Попытка доступа к элементу с некорректным индексом
            List<String> items = new ArrayList<>();
            items.add("item1");
            String item = items.get(5);  // ArrayIndexOutOfBoundsException
        } catch (IndexOutOfBoundsException e) {
            System.out.println("Индекс вне границ коллекции");
        }
    }
}

3. Безопасное преобразование типов

public class SafeCastExample {
    public static void processObject(Object obj) {
        try {
            if (obj instanceof String) {
                String str = (String) obj;  // Безопасно
                System.out.println("Строка: " + str);
            } else {
                // Если не использовать instanceof
                Integer num = (Integer) obj;  // Может быть CCE
            }
        } catch (ClassCastException e) {
            System.out.println("Неверное преобразование типа");
        }
    }
}

4. Несколько catch блоков для разных исключений

public class MultiCatchExample {
    public static void processData(String[] data, String index) {
        try {
            int idx = Integer.parseInt(index);     // Может выбросить NFE
            String value = data[idx];               // Может выбросить AIOOBE
            System.out.println(value);
        } catch (NumberFormatException e) {
            System.out.println("Индекс — не число");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Индекс вне границ массива");
        } catch (RuntimeException e) {
            System.out.println("Другая ошибка: " + e.getClass().getName());
        }
    }
}

5. Multi-catch синтаксис (Java 7+)

public class MultiCatchSyntax {
    public static void process(String input) {
        try {
            int number = Integer.parseInt(input);
            int result = 100 / number;
        } catch (NumberFormatException | ArithmeticException e) {
            // Обрабатываем оба исключения одинаково
            System.out.println("Ошибка обработки: " + e.getMessage());
        }
    }
}

Следует ли перехватывать Unchecked исключения?

✅ ДА, перехватывайте, если:

  1. Вы хотите восстановиться после ошибки
  2. Нужна специальная обработка определённой ошибки
  3. Требуется логирование или очистка ресурсов
public void safeOperation() {
    try {
        riskyOperation();  // Может выбросить NPE
    } catch (NullPointerException e) {
        logger.warn("Обнаружена null ссылка", e);
        useDefaultValue();  // Восстановление
    }
}

❌ НЕ перехватывайте слепо, если:

  1. Просто скрываете ошибку (bad practice)
  2. Не знаете, как обработать
  3. Можете избежать исключения проверкой
// ❌ Плохо — скрываем проблему
try {
    String text = null;
    System.out.println(text.length());
} catch (NullPointerException e) {
    // Молчим, как будто ничего не произошло
}

// ✅ Хорошо — проверяем перед использованием
if (text != null) {
    System.out.println(text.length());
}

Best Practices

public class BestPractices {
    
    // ✅ Специфичная обработка
    public void goodCatch(String[] args) {
        try {
            int index = Integer.parseInt(args[0]);
        } catch (NumberFormatException e) {
            System.out.println("Пожалуйста, передайте число");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Пожалуйста, передайте аргумент");
        }
    }
    
    // ❌ Слишком общая обработка
    public void badCatch(String[] args) {
        try {
            int index = Integer.parseInt(args[0]);
        } catch (Exception e) {  // Слишком общо!
            System.out.println("Ошибка");
        }
    }
    
    // ✅ Проверка вместо перехвата, где возможно
    public void preventException(String text) {
        if (text != null && !text.isEmpty()) {
            System.out.println(text.length());
        }
    }
}

Таблица сравнения

ХарактеристикаCheckedUnchecked
Обязательная обработка✅ Да❌ Нет
Можно перехватить✅ Да✅ Да
Можно перебросить✅ Да✅ Да
Типичные примерыIOException, SQLExceptionNPE, AIOOBE
Когда выбрасываетсяAPI должен указатьМожет быть в любом месте

Вывод

Да, непроверяемые исключения полностью перехватываются. Разница только в том, что:

  • Checked — компилятор требует обработки (throws или try-catch)
  • Unchecked — компилятор не требует обработки, но она возможна

Стратегия:

  1. Перехватывайте только те исключения, которые можете обработать
  2. Используйте проверки вместо перехвата (if != null)
  3. Логируйте и восстанавливайтесь, где это имеет смысл
  4. Избегайте слепого перехвата общих Exception/RuntimeException классов
Можно ли перехватывать непроверяемые исключения? | PrepBro