«1. Обзор

В этом руководстве мы сосредоточимся на глобальном обработчике исключений в Java. Сначала мы обсудим основы исключений и их обработку. Затем мы всесторонне рассмотрим глобальный обработчик исключений.

Чтобы узнать больше об исключениях в целом, взгляните на Обработку исключений в Java.

2. Что такое исключение?

Исключение — это ненормальное состояние, возникающее в последовательности кода во время выполнения или во время компиляции. Это ненормальное состояние возникает, когда программа нарушает семантические ограничения языка программирования Java.

Исключения, возникающие во время компиляции, являются проверенными исключениями. Эти исключения являются прямыми подклассами класса Exception, и необходимо обрабатывать эти исключения в коде.

Другим типом исключений являются непроверенные исключения. Компилятор не проверяет эти исключения во время компиляции. Эти исключения являются прямыми подклассами класса RuntimeException, который расширяет класс Exception.

Кроме того, нет необходимости обрабатывать исключения во время выполнения в коде.

3. Обработчики исключений

Java — надежный язык программирования. Одной из основных функций, которая делает его надежным, является структура обработки исключений. Это означает, что программа может корректно завершать работу во время ошибки, а не просто падать.

Всякий раз, когда возникает исключение, объект Exception создается либо JVM, либо методом, выполняющим код. Этот объект содержит информацию об исключении. Обработка исключений — это способ обработки этого объекта исключения.

3.1. Блок try-catch

В следующем примере блок try содержит код, который может генерировать исключение. Блок catch содержит логику для обработки этого исключения.

Блок catch перехватывает объект Exception, который вызывается кодом в блоке try:

String string = "01, , 2010";
DateFormat format = new SimpleDateFormat("MM, dd, yyyy");
Date date;
try {
    date = format.parse(string);
} catch (ParseException e) {
    System.out.println("ParseException caught!");
}

3.2. Ключевые слова throw и throws

Кроме того, метод также может выбрать генерацию исключения вместо его обработки. Это означает, что логика для обработки объекта Exception написана где-то еще.

Обычно в таких случаях исключение обрабатывает вызывающий метод:

public class ExceptionHandler {

    public static void main(String[] args) {

        String strDate = "01, , 2010";
        String dateFormat = "MM, dd, yyyy";
		
        try {
            Date date = new DateParser().getParsedDate(strDate, dateFormat);
        } catch (ParseException e) {
            System.out.println("The calling method caught ParseException!");
        }
    }
}

class DateParser {
	
    public Date getParsedDate(String strDate, String dateFormat) throws ParseException {
        DateFormat format = new SimpleDateFormat(dateFormat);
        
        try {
            return format.parse(strDate);
        } catch (ParseException parseException) {
            throw parseException;
        }		
    }
	
}

Далее мы рассмотрим глобальный обработчик исключений как универсальный способ обработки исключений.

4. Глобальный обработчик исключений

Экземпляры RuntimeException необязательны для обработки. Следовательно, он по-прежнему оставляет окно открытым для получения длинных трассировок стека во время выполнения. Для этого в Java предусмотрен интерфейс UncaughtExceptionHandler. Класс Thread содержит это как внутренний класс.

В дополнение к этому интерфейсу в выпуске Java 1.5 также появился статический метод setDefaultUncaughtExceptionHandler() в классе Thread. Аргументом этого метода является класс-обработчик, реализующий интерфейс UncaughtExceptionHandler.

Кроме того, этот интерфейс объявляет метод uncaughtException(Thread t, Throwable e). Он будет вызываться, когда данный поток t завершается из-за данного необработанного исключения e. Класс реализации реализует этот метод и определяет логику обработки этих необработанных исключений.

Давайте рассмотрим следующий пример, который выдает исключение ArithmeticException во время выполнения. Мы определяем класс Handler, реализующий интерфейс UncaughtExceptionHandler.

Этот класс реализует метод uncaughtException() и определяет в нем логику обработки неперехваченных исключений:

public class GlobalExceptionHandler {

    public static void main(String[] args) {

        Handler globalExceptionHandler = new Handler();
        Thread.setDefaultUncaughtExceptionHandler(globalExceptionHandler);
        new GlobalExceptionHandler().performArithmeticOperation(10, 0);
    }

    public int performArithmeticOperation(int num1, int num2) {
        return num1/num2;
    }
}

class Handler implements Thread.UncaughtExceptionHandler {

    private static Logger LOGGER = LoggerFactory.getLogger(Handler.class);

    public void uncaughtException(Thread t, Throwable e) {
        LOGGER.info("Unhandled exception caught!");
    }
}

Здесь текущий выполняемый поток является основным потоком. Таким образом, его экземпляр передается в метод uncaughtException() вместе с возникшим исключением. Затем класс Handler обрабатывает это исключение.

То же самое относится и к необработанным проверенным исключениям. Давайте также рассмотрим быстрый пример этого:

public static void main(String[] args) throws Exception {
    Handler globalExceptionHandler = new Handler();
    Thread.setDefaultUncaughtExceptionHandler(globalExceptionHandler);
    Path file = Paths.get("");
    Files.delete(file);
}

Здесь метод Files.delete() генерирует проверенное исключение IOException, которое далее генерируется сигнатурой метода main(). Обработчик также поймает это исключение.

«Таким образом, UncaughtExceptionHandler помогает управлять необработанными исключениями во время выполнения. Однако это разрушает идею перехвата и обработки исключения вблизи точки его возникновения.

5. Заключение

В этой статье мы уделили время тому, чтобы понять, что такое исключения, и каковы основные способы их обработки. Кроме того, мы определили, что глобальный обработчик исключений является частью класса Thread и обрабатывает неперехваченные исключения времени выполнения.

Затем мы увидели пример программы, которая создает исключение во время выполнения и обрабатывает его с помощью глобального обработчика исключений.

Примеры кода для этой статьи можно найти на GitHub.