Open3

java, kotlin 「抑制された例外」って何?

ふじしろふじしろ

概要

  • 抑制された例外:主たる例外がスローされている間に発生した追加の例外。
  • 目的:複数の例外情報を失わずに保持し、デバッグを容易にする。
  • 取得方法:Throwable.getSuppressed()(Java)、Throwable.suppressedプロパティ(Kotlin)を使用。

Kotlinの非同期処理における抑制された例外に関するメモ

  • Kotlinでは非同期処理でも発生したりする。
    • Coroutine内(子スレッド)で発生した例外は、外側でリクエストを実処理している親スレッドに通知されずに(=抑制されて)処理されていたりする。
  • 親子スレッドにはそれぞれ責務があるので、子スレッドが適切にハンドリングできなかった例外を親スレッドがこじ開けて確認するようなことは無意味なので、抑制された例外があるとして、それを確認する必要があるかどうかは検討する必要がある。
  • Coroutine中で起こったことはその中でハンドリングし切る、外側には処理続行・停止に関わる成否だけ伝え、外側から内側の詳細をハンドリングしなくてよくする

  • Coroutine内:外部へのリクエストで起こった例外がもれなくハンドリングされてResultとして親スレッドに返る
  • Coroutine外:メインスレッドでResultに応じて処理を続行したり、例外を発行してGlobalExceptionHandlerに拾わせる
ふじしろふじしろ

AIの回答

Java(Java 7以降)およびKotlinにおける「抑制された例外」とは、主にリソースの自動管理中に複数の例外が発生した場合に、一方の例外が他方の例外に「抑制」されて付加される機能を指します。これは、例外の情報が失われるのを防ぎ、デバッグやエラーハンドリングを容易にするための仕組みです。

Javaの場合

Java 7で導入されたtry-with-resources文を使用すると、AutoCloseableを実装したリソース(例えば、ファイルやネットワークソケットなど)を自動的に閉じることができます。この際、以下のようなシナリオが考えられます:

  1. tryブロック内で例外Aが発生
  2. リソースを閉じる際に例外Bが発生

従来のJavaでは、例外Bが例外Aを上書きしてしまい、元の例外情報が失われる問題がありました。Java 7以降では、この問題を解決するために、例外Bを例外Aの「抑制された例外」として追加します。これにより、例外Aをスローしつつ、例外Bの情報も保持できます。

抑制された例外は、ThrowableクラスのgetSuppressed()メソッドを使用して取得できます。

例:

try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    // ファイル読み込み中に例外が発生する可能性あり
    String line = br.readLine();
} catch (IOException e) {
    e.printStackTrace();
    for (Throwable suppressed : e.getSuppressed()) {
        System.out.println("Suppressed: " + suppressed);
    }
}

Kotlinの場合

Kotlinでも同様の概念が存在し、use関数を使用してリソースを自動的に閉じることができます。use関数は拡張関数であり、CloseableAutoCloseableを実装したオブジェクトに適用できます。

例:

FileReader("file.txt").buffered().use { reader ->
    // ファイル読み込み中に例外が発生する可能性あり
    val line = reader.readLine()
}

この場合も、読み込み中に例外が発生し、さらにuse関数によるリソース解放中に別の例外が発生した場合、後者の例外は前者の例外に「抑制された例外」として追加されます。

まとめ

  • 抑制された例外:主たる例外がスローされている間に発生した追加の例外。
  • 目的:複数の例外情報を失わずに保持し、デバッグを容易にする。
  • 取得方法Throwable.getSuppressed()(Java)、Throwable.suppressedプロパティ(Kotlin)を使用。

この機能により、リソース管理中の例外処理がより安全かつ情報豊かになります。

ふじしろふじしろ

Coroutine解説:例外の集約
https://kotlinlang.org/docs/exception-handling.html#exceptions-aggregation

例外の集約
コルーチンの複数の子プロセスが例外で失敗した場合、一般的なルールは「最初の例外が勝つ」なので、最初の例外が処理される。 そのため、最初の例外が処理されます。最初の例外の後に発生した追加の例外は、抑制された例外として最初の例外に付加されます。

CoroutineExceptionHandler リファレンス
https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/