23

私は Java 6 で SwingWorker を使用して、イベント ディスパッチ スレッドで実行時間の長いコードを実行しないようにしています。

done() メソッドで get() を呼び出したときに例外が返された場合、例外を処理する適切な方法は何ですか?

可能性のある InterruptedExceptions について特に心配しています。JavaDoc の例では単に例外を無視していますが、例外を飲み込むとデバッグが困難なコードになることを私は何年にもわたって学びました。

使用例は次のとおりです。

new SwingWorker<String, Void>() {

    @Override
    protected String doInBackground() throws Exception {
        // do long-running calculation
        return result;
    }

    @Override
    protected void done() {
        try {
            setTextField(get());
        } catch (InterruptedException e) {
            e.printStackTrace();  
        } catch (ExecutionException e) {
            e.printStackTrace();  
        }
    }
}.execute();
4

7 に答える 7

12

これは古い投稿ですが、いくつか明確にしたいと思います。

SwingWorker.get は、InterruptedException、ExecutionException をチェック例外としてスローします。

さらに、CancellationException という非常に具体的な未チェックの例外をスローします。もちろん、チェックされていない例外をスローする可能性はありますが、CancellationException は「例外的」で予期しないものではありません。キャンセル後に get メソッドを呼び出そうとするとスローされます。

doInBackground 内で例外がスローされると、ExecutedException がスローされます。元の例外は、ExecutionException 内にラップされます。get() メソッドが呼び出されると、ExecutionException がスローされます。元の例外を取り出して管理するというアイデアは良いです。(Emil Hが指摘したように)。

CancellationException はチェックされておらず、私の意見ではチェックする必要があります。API 実装がチェックされていない唯一の言い訳は、ステータス メソッド isCancelled() があることです。
次のいずれかを実行できます:
- isCancelled() をテストし、true の場合は get() を呼び出さないでください。CancellationException がスローされるためです
- get() を try-catch で囲み、CancellationException を追加します
。 CancellationException はチェックされていないので、そのすべてを忘れて、素晴らしい驚きを得ることができます。
-ワーカーをキャンセルしないため、何でもします

中断された例外。cancel(true) で SwingThread をキャンセルすると、doInBackground の最初の割り込み可能なメソッド呼び出し (確かに Thread.sleep、this.wait、おそらくいくつかの IO メソッド) で InterruptException がスローされます。ただし、この例外は ExecuteException にラップされません。doInBackground は、中断された例外で終了するために残されます。それがキャッチされて他の例外に変換された場合、それらは無視されます。これは、この時点で cancel が EDT で SwingThread.done を既に呼び出しており、done が get を呼び出した場合、標準の CancellationException だけを取得しているためです。InterruptedException ではありません。

cancel(false) でキャンセルすると、doInBackground 内で InterruptException は発生しません。cancel(true) でキャンセルした場合も同じですが、doInBackground 内に割り込み可能なメソッド呼び出しはありません。これらの場合、doInBackground はその自然なループに従います。このループは isCancelled メソッドをテストし、正常に終了する必要があります。doInBackground がそうしない場合、永久に実行されます。タイムアウトの存在についてはテストしていませんが、そうは思いません。

私にとっては、グレーゾーンのままです。get によって InterruptedException がスローされるのはどのような場合ですか? 同様の例外を生成できなかったので、短いコードを見たいと思います。:-)

PS別の質問と回答で、キャンセルの場合の完了および状態変更リスナーがdoInBackgroundが終了する前に呼び出されることを文書化しました。これは事実であるため、これはバグではありませんが、doInBackground メソッドを設計する際には特別な注意が必要です。これに興味がある場合は、SwingWorker: 正確に done メソッドが呼び出されるのはいつですか?を参照してください。

于 2011-06-03T18:44:07.530 に答える
3

これは、バックグラウンド ジョブが原因で発生する可能性のあるエラーの種類に大きく依存します。doInBackground のジョブが例外をスローすると、ネストされた ExecutionException として done メソッドに伝播されます。この場合のベスト プラクティスは、ExecutionException 自体ではなく、ネストされた例外を処理することです。

例: ワーカー スレッドが、データベース接続が失われたことを示す例外をスローした場合、おそらく再接続してジョブを再開する必要があります。実行される作業が、すでに使用されていることが判明したある種のリソースに依存している場合は、使用に再試行またはキャンセルの選択肢を提供することをお勧めします。スローされた例外がユーザーに影響を与えない場合は、エラーをログに記録して続行します。

私が覚えている限りでは、InterruptedException は、done メソッドで get メソッド呼び出しを行うため、ここでは問題にならないと考えています。終了。そのような予期しないイベントが発生した場合、おそらくエラー メッセージを表示してアプリケーションを終了したいと思うでしょう。

于 2009-04-26T17:51:34.040 に答える
2

これは、エラー処理の問題であると同時にインターフェースの問題でもあります。多くのアプリは、実行中のバックグラウンド ジョブを一覧表示する小さなテーブルを追加します。それらのいずれかで例外が発生すると、エラーを生成したテーブル行がフラッシュされたり、アラートが表示されるなどの破壊的なことが行われる可能性があります。例外の重大度によって異なります。おそらく答えなければならない難しい質問は、潜在的に異なるタイプの例外がいくつあり、それらの相対的な重大度はどのくらいかということです。

簡単な妥協案は、最も重大なエラーに対してモーダル アラートを表示することであり、それ以外の場合は、a) ユーザーが先に進むのをブロックするか、b) ユーザーがドキュメント/ウィンドウを閉じるまで、単に発生を記録することであると思います。たとえば、保存されていないバッファを保存するかどうかを尋ねると同時に、バックグラウンド処理タスク中に発生した例外のリストを表示できます。

于 2009-04-28T05:07:00.663 に答える
2

私がお勧めするのは、アクションが開始された場所までエラーを伝播させることです。

たとえば、ユーザーがボタンをクリックして、データ ソースからデータをフェッチしたとします。資格情報エラー、ネットワーク エラー、データベース エラーなど、問題が発生した場合、そのワーカー スレッド内にその場で解決しようとするロジックを用意するのは適切ではありません。

ただし、タスクが開始された場所に伝播させると、そこから適切なエラー修正を行うことができます。たとえば、資格情報ダイアログをもう一度ポップしたり、「再試行」ダイアログを表示したり、エラー メッセージを表示したりすることもできます。

于 2009-05-02T05:58:24.250 に答える
0

これが GUI アプリケーションであると仮定すると、例外発生時に失敗した操作に関する視覚的なフィードバックを提供することができます。

于 2009-04-26T17:20:18.610 に答える
-2

C# では、これらの質問の多くは得られないと思います。例外が何であるかを理解し、適切に処理する必要があります (これは通常、例外をスタックの上位に移動させるためです)。

InterruptedExceptionThread.interrupt-待機中 (大まかに) にスレッドが (によって) 割り込まれたときにスローされます。スレッドを中断する必要があるのはなぜですか? 通常、スレッドが実行していることを停止する必要があります-割り込み状態をリセットして終了します。たとえば、プラグインは、アプレットがなくなった後にアプレット スレッドが長時間続くと、アプレット スレッドを中断します。ただし、この場合、提供されたdoneものが正しく呼び出されている場合は、待機する必要はまったくありません。したがって、例外を でラップすることが適切ですIllegalStateException(そして、API ドキュメントはおそらくそれを述べているはずです)。それは本当に悪い API です。publish/モードはprocessおそらくより理にかなっています。

ExecutionException- ラップされた例外を処理する必要があります。特定のタイプの例外が予期されていない場合は、未チェックの例外でラップします。

一般的に、EDT で発生することと EDT 以外で発生することを明確に区別することをお勧めします。したがって、SwingWorker製品コードでは避けてください。

于 2009-04-26T19:07:09.883 に答える