1. 概要

このチュートリアルでは、Javaのグローバル例外ハンドラーに焦点を当てます。 まず、例外の基本と例外処理について説明します。 次に、グローバル例外ハンドラーを包括的に見ていきます。

一般的な例外の詳細については、Javaでの例外処理を参照してください。

2. 例外とは何ですか?

例外は、実行時またはコンパイル時にコードシーケンスで発生する異常な状態です。この異常な状態は、プログラムがJavaプログラミング言語のセマンティック制約に違反した場合に発生します。

コンパイル時に発生する例外はチェック例外です。これらの例外はExceptionクラスの直接のサブクラスであり、コードでこれらの例外を処理する必要があります。

別のタイプの例外は、チェックされていない例外です。 コンパイラは、コンパイル時にこれらの例外をチェックしません。 これらの例外は、 RuntimeException を拡張するクラス例外クラス。

また、コードで実行時例外を処理する必要はありません。

3. 例外ハンドラ

Javaは堅牢なプログラミング言語です。 堅牢にするコア機能の1つは、例外処理フレームワークです。 これは、プログラムが単にクラッシュするのではなく、エラー時に正常に終了できることを意味します。

例外が発生するたびに、JVMまたはコードを実行するメソッドのいずれかによってExceptionオブジェクトが構築されます。 このオブジェクトには、例外に関する情報が含まれています。 例外処理は、この例外オブジェクトを処理する方法です。

3.1. try-catchブロック

次の例では、 try ブロックに、例外をスローする可能性のあるコードが含まれています。 catch ブロックには、この例外を処理するためのロジックが含まれています。

catch ブロックは、tryブロックのコードが発生するExceptionオブジェクトをキャッチします。

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. スローおよびスローキーワード

または、メソッドは、例外を処理する代わりに、例外をスローすることを選択することもできます。 つまり、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()も導入されました。 このメソッドの引数は、UncaughtExceptionHandlerインターフェイスを実装するハンドラークラスです。

さらに、このインターフェイスは、メソッド uncaughtException(Thread t、Throwable e)を宣言します。 これは、指定されたキャッチされない例外eが原因で指定されたスレッドtが終了したときに呼び出されます。 実装クラスはこのメソッドを実装し、これらのキャッチされない例外を処理するためのロジックを定義します。

実行時にArithmeticExceptionをスローする次の例を考えてみましょう。 インターフェイスUncaughtExceptionHandlerを実装するクラスHandlerを定義します。

このクラスは、メソッド 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にあります。