ちょっと、私はネットワークアプリケーションを書いています。そこでは、カスタムバイナリフォーマットのパケットを読み取ります。そして、受信データを待機するバックグラウンドスレッドを開始しています。問題は、コンパイラがrun()
に例外をスロー(チェック)するコードを入れさせないことです。それは言います:
(...)。Listenerのrun()は、Java.lang.Runnableのrun()を実装できません。オーバーライドされたメソッドはJava.io.IOExceptionをスローしません
例外を使用してスレッドを強制終了し、親スレッドのどこかにキャッチさせます。これを達成することは可能ですか、すべての例外を処理する必要がありますか?内部スレッド?
警告:例外メカニズムを使用する必要がある場合、これはニーズを満たさない場合があります。
私があなたを正しく理解していれば、実際に例外をチェックする必要はありません(チェックされていない例外を示唆する答えを受け入れました)ので、単純なリスナーパターンがより適切ですか?
リスナーは親スレッドに住むことができ、子スレッドでチェック例外をキャッチしたら、リスナーに通知するだけで済みます。
これは、(パブリックメソッドを介して)これが発生することを公開する方法があり、例外で許可されるよりも多くの情報を渡すことができることを意味します。しかし、親スレッドと子スレッドの間に(ゆるいものではあるが)カップリングが存在することを意味します。特定の状況では、チェック済みの例外を未チェックの例外でラップするよりもメリットがあるかどうかによって異なります。
次に簡単な例を示します(一部のコードは別の回答から借用しています)。
public class ThingRunnable implements Runnable {
private SomeListenerType listener;
// assign listener somewhere
public void run() {
try {
while(iHaveMorePackets()) {
doStuffWithPacket();
}
} catch(Exception e) {
listener.notifyThatDarnedExceptionHappened(...);
}
}
}
結合は、SomeListenerType
型である必要がある親スレッド内のオブジェクトから発生します。
親スレッドに例外を送信できるようにするには、バックグラウンドスレッドを Callable (チェック済み例外もスローできます)に入れてから submit に渡します。 一部のエグゼキューター のメソッド。 submitメソッドは Future を返し、これを使用して例外を取得できます(その get メソッドは元の例外を含む ExecutionException をスローします)。
この回答はEsko Luontolaのものに基づいていますが、実際の例を提供します。
Runnableインターフェースのrun()メソッドとは異なり、Callableのcall()メソッドではいくつかの例外をスローできます。実装例は次のとおりです。
public class MyTask implements Callable<Integer> {
private int numerator;
private int denominator;
public MyTask(int n, int d) {
this.numerator = n;
this.denominator = d;
}
@Override
// The call method may throw an exception
public Integer call() throws Exception {
Thread.sleep(1000);
if (denominator == 0) {
throw new Exception("cannot devide by zero");
} else {
return numerator / denominator;
}
}
}
Executorは、スレッド内でCallableを実行し、あらゆる種類の例外を処理するメカニズムを提供します。
public class Main {
public static void main(String[] args) {
// Build a task and an executor
MyTask task = new MyTask(2, 0);
ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
try {
// Start task on another thread
Future<Integer> futureResult = threadExecutor.submit(task);
// While task is running you can do asynchronous operations
System.out.println("Something that doesn't need the tasks result");
// Now wait until the result is available
int result = futureResult.get();
System.out.println("The result is " + result);
} catch (ExecutionException e) {
// Handle the exception thrown by the child thread
if (e.getMessage().contains("cannot devide by zero"))
System.out.println("error in child thread caused by zero division");
} catch (InterruptedException e) {
// This exception is thrown if the child thread is interrupted.
e.printStackTrace();
}
}
}
私がしていることは、スレッドで例外をキャッチし、Runnableのメンバー変数として保存することです。この例外は、Runnableのゲッターを介して公開されます。次に、親からのすべてのスレッドをスキャンして、例外があるかどうかを確認し、適切なアクションを実行します。
例外が発生したときに本当に役立つことを何もできない場合は、チェックされた例外をRuntimeExceptionにラップできます。
try {
// stuff
} catch (CheckedException yourCheckedException) {
throw new RuntimeException("Something to explain what is happening", yourCheckedException);
}
スレッドは他のスレッド(またはメインスレッド)に例外をスローできません。また、継承されたrun()メソッドでチェック済み例外をスローすることはできません。スローできるのは継承されたコードよりも少なく、それ以上ではないためです。
スレッドのコードがRuntimeExpectionをスローする場合、run()throw Exceptionを追加する必要はありません。
ただし、適切な場合にのみ、このソリューションを使用してください。これは悪い習慣になる可能性があるためです。 http://Java.Sun.com/docs/books/tutorial/essential/exceptions/runtime.html
RuntimeExceptionまたは未チェックの例外が役立ちます。たぶん、あなたはあなた自身のRuntimeExceptionを作成する必要があるでしょう
コードが何らかのループにあると仮定して、次のように記述します。
public class ThingRunnable implements Runnable {
public void run() {
try {
while(iHaveMorePackets()) {
doStuffWithPacket()
}
} catch(Exception e) {
System.out.println("Runnable terminating with exception" + e );
}
}
}
例外は自動的にループから抜け出し、run()メソッドの最後でスレッドが停止します。