2

CLR(C#、VB.NETなどで使用されるランタイム)には、未処理の例外がスローされたときに呼び出されるコールバックを登録する方法があります。

Javaに似たようなものはありますか?

おそらく、単一のメソッドで何らかのインターフェイスを実装するオブジェクトを渡すAPIになると思います。例外がスローcatchされ、スタックに一致するものがない場合、ランタイムは登録されたオブジェクトのメソッドを呼び出し、例外オブジェクトが渡されます。

これにより、プログラマーはスタックトレースを保存できます。また、未処理の例外に対してのみ実行されるブロックSystem.exitを停止するために、を呼び出すこともできます。finally

アップデート1。

これを説明するために、C#のサンプルを次に示します。

// register custom handler for unhandled exceptions
AppDomain.CurrentDomain.UnhandledException += (sender, evt) =>
{
    Console.WriteLine("unhandled exception");
    Environment.FailFast(null);
};

try
{
    throw new NullReferenceException();
}
finally
{
    Console.WriteLine("finally is executing");
}

重要なのは、私に電話をかけることで、ブロックの実行Environment.FailFast(null)を停止できるということです。finally

案の定、Windows7で実行されているNET3.5および4.0では、出力に「finallyisexecuting」という文字列が表示されません。FailFastしかし、呼び出しをコメントアウトすると、出力にその文字列が表示されます。

アップデート2。

これまでの回答に基づいて、これをJavaで再現する試みを示します。

// register custom handler for unhandled exceptions
Thread.currentThread().setUncaughtExceptionHandler(

    new Thread.UncaughtExceptionHandler() {

        public void uncaughtException(
                final Thread t, final Throwable e) {

            System.out.println("Uncaught exception");
            System.exit(0);
        }
    }
);

try
{
    throw new NullPointerException();
}
finally
{
    System.out.println("finally is executing");
}

これをJava6(1.6.0_18)で実行すると、次のように表示されます。

  • ついに実行中
  • 捕捉されなかった例外

つまり、JREはfinally、キャッチされない例外ハンドラーを実行する前にブロックを実行します。

これが重要である理由の背景については、より複雑な例を次に示します。

try
{
    try
    {
        throw new NullPointerException();
    }
    finally
    {
        System.out.println("finally is executing");
        throw new java.io.IOException();
    }
}
catch (java.io.IOException x)
{
    System.out.println("caught IOException");
}

System.out.println("program keeps running as if nothing had happened...");

したがって、重大なバグがあり、プログラムを停止してスタックトレースをログに記録したいと思います。しかし、これを行う前に、スタックのどこかに中間finallyブロックがあり(実際のプログラムでは、別のメソッドになります)、ファイルシステムにアクセスしようとします。何かがおかしい。次に、スタックの少し上に、IOException私にとって大したことではないので、私がキャッチを持っていると仮定します。

言うまでもなく、出力は次のとおりです。

  • ついに実行中
  • IOExceptionをキャッチしました
  • プログラムは何も起こらなかったかのように実行し続けます...

だから今、私は偶然に深刻なバグが私から隠されている状況を作り出しました。

2つの解決策があります:

  • どういうわけか、ブロックが安全かどうかをローカルで判断できないため、finallyブロックがスローされないようにします。通常の実行パスをスローしても問題がないため、これは残念です。つまり、前の例外に応答して実行されていない場合です。
  • finallyキャッチされない例外がある場合にブロックを実行したくないことをランタイムに通知します。

後者が利用可能であれば、確かに私の好みです。

4

1 に答える 1

7

を参照してくださいThread.setUncaughtExceptionHandler()

更新:結局のところ、「未処理/未処理の例外」は、C#とJavaではわずかに異なることを意味しているようです。一見すると、あなたが説明する動作は、Javaでは(残念ながら)正常に見えます。

キャッチされない例外が原因でこのスレッドが突然終了したときに呼び出されるハンドラーを設定します。

つまり、キャッチされなかった例外ハンドラーは、例外がユーザーコードからスレッドに伝播されたときに呼び出されます。finallyこれは、適切に実行されたブロックを含むメソッドを残したことを意味します。

AFAIKfinallyブロックは常にJavaで実行されるため、オプション2は実行可能ではありません。

以下の議論からの結論

オプション1-ブロックに何もスローしないfinally-制限はありますが、唯一の本当の長期的な解決策のようです。

明らかにロギング部分については、オプション3があります。

try
{
    try
    {
        throw new NullPointerException();
    }
    catch (Exception x)
    {
        System.out.println("caught Exception" + x.getMessage());
        x.printStackTrace();
        throw x; // keep original behaviour
    }
    finally
    {
        System.out.println("finally is executing");
        throw new java.io.IOException();
    }
}
catch (java.io.IOException x)
{
    System.out.println("caught IOException");
}

于 2010-06-21T15:52:04.113 に答える