Javaグローバル例外ハンドラ
1概要
このチュートリアルでは、Javaのグローバル例外ハンドラに焦点を当てます。
最初に、例外の基本と例外処理について説明します。それでは、グローバル例外ハンドラについて包括的に説明します。
一般的な例外の詳細については、https://www.baeldung.com/java-exceptions[Javaでの例外処理]を参照してください。
** 2例外とは
-
例外とは、実行時またはコンパイル時にコードシーケンスで発生する異常な状態です。** この異常な状態は、プログラムがJavaプログラミング言語の意味上の制約に違反しているときに発生します。
-
コンパイル時に発生する例外は
チェックされた例外
です。** これらの例外は
Exception
クラスの直接のサブクラスであり、コードでこれらの例外を処理する必要があります。 -
別の種類の例外は
未チェックの例外
です。コンパイラは、コンパイル時にこれらの例外をチェックしません。** これらの例外は、
Exception
クラスを拡張する
RuntimeException
クラスの直接のサブクラスです。
また、コード内でランタイム例外を処理する必要はありません。
3例外ハンドラ
Javaは堅牢なプログラミング言語です。それを堅牢にするコア機能の1つは、例外処理フレームワークです。これは、プログラムが単にクラッシュするのではなく、エラー時に正常に終了できることを意味します。
-
例外が発生するたびに、JVMまたはコードを実行するメソッドによって
Exception
オブジェクトが構築されます。このオブジェクトは例外についての情報が含まれています。 ** 例外処理は、この
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.
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
interface
を提供します。 Thread__クラスはこれを内部クラスとして含みます。
このインタフェースに加えて、Java 1.5リリースでは
Thread
クラスに静的メソッド
setDefaultUncaughtExceptionHandler()
も導入されました。このメソッドの引数は、
UncaughtExceptionHandler
インタフェースを実装するハンドラクラスです。
さらに、このインタフェースはメソッド
uncaughtException(Thread t、Throwable e)
を宣言しています。指定されたスレッド
t
が、指定されたキャッチされていない例外
e
のために終了したときに呼び出されます。実装クラスはこのメソッドを実装し、これらの捕捉されていない例外を処理するためのロジックを定義します。
実行時に
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()メソッドシグネチャによってスローされます。
Handler__もこの例外をキャッチします。
このように、
UncaughtExceptionHandler
は、実行時に未処理の例外を管理するのに役立ちます。しかし、それは例外を捕捉して起点の近くで処理するという考えを壊します。
5結論
この記事では、例外とは何か、そしてそれらを処理する基本的な方法は何かを理解するのに時間がかかりました。また、グローバル例外ハンドラは
Thread
クラスの一部であり、キャッチされていないランタイム例外を処理することを確認しました。
次に、ランタイム例外をスローし、グローバル例外ハンドラを使用して処理するサンプルプログラムを見ました。
この記事のコード例はhttps://github.com/eugenp/tutorials/tree/master/core-java[GitHubで利用可能]です。