私は次のコードを持っています:
// How to throw the ServerException?
public void myFunc() throws ServerException{
// Some code
CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
try {
return someObj.someFunc();
} catch(ServerException ex) {
// throw ex; gives an error here.
}
}));
// Some code
}
someFunc()
はServerException
をスローします。ここでは処理しませんが、someFunc()
からmyFunc()
の呼び出し元に例外をスローします。
コードでは、非同期操作の結果を後で同じメソッドで使用することを提案しているため、CompletionException
を処理する必要があるため、それを処理する1つの方法は
public void myFunc() throws ServerException {
// Some code
CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
try { return someObj.someFunc(); }
catch(ServerException ex) { throw new CompletionException(ex); }
});
// Some code running in parallel to someFunc()
A resultOfA;
try {
resultOfA = a.join();
}
catch(CompletionException ex) {
try {
throw ex.getCause();
}
catch(Error|RuntimeException|ServerException possible) {
throw possible;
}
catch(Throwable impossible) {
throw new AssertionError(impossible);
}
}
// some code using resultOfA
}
Supplier
の非同期処理内でスローされたすべての例外は、CompletionException
を呼び出すときにjoin
にラップされます。ただし、ServerException
に既にラップされているCompletionException
。
CompletionException
の原因を再スローすると、未チェックの例外、つまりError
またはRuntimeException
のサブクラス、またはカスタムのチェック済み例外ServerException
に直面する可能性があります。上記のコードは、すべてをそれらを再キャッチするマルチキャッチで処理します。 getCause()
の宣言された戻り値の型はThrowable
であるため、考えられるすべての型を既に処理したにもかかわらず、コンパイラはその型を処理することを要求します。簡単な解決策は、AssertionError
にラップされたこの実際には不可能なスロー可能オブジェクトをスローすることです。
あるいは、カスタム例外に将来の代替結果を使用することもできます。
public void myFunc() throws ServerException {
// Some code
CompletableFuture<ServerException> exception = new CompletableFuture<>();
CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
try { return someObj.someFunc(); }
catch(ServerException ex) {
exception.complete(ex);
throw new CompletionException(ex);
}
});
// Some code running in parallel to someFunc()
A resultOfA;
try {
resultOfA = a.join();
}
catch(CompletionException ex) {
if(exception.isDone()) throw exception.join();
throw ex;
}
// some code using resultOfA
}
このソリューションは、すべての「予期しない」スロー可能オブジェクトをラップされた形式で再スローしますが、ServerException
futureを介して渡された元の形式のカスタムexception
のみをスローします。競合状態を避けるために、a
futureをクエリする前に、exception
が完了していることを確認する必要があることに注意してください(最初にjoin()
を呼び出すように)。
CompletableFutureを使用した例外処理で他の方法を探している人向け
以下は、整数への解析エラーを処理する例のいくつかの方法です。
1。 handle
メソッドの使用-例外のデフォルト値を提供できます
CompletableFuture correctHandler = CompletableFuture.supplyAsync(() -> "A")
.thenApply(Integer::parseInt)
.handle((result, ex) -> {
if (null != ex) {
ex.printStackTrace();
return 0;
} else {
System.out.println("HANDLING " + result);
return result;
}
})
.thenAcceptAsync(s -> {
System.out.println("CORRECT: " + s);
});
2。 exceptionally
メソッドを使用する-handle
に似ていますが、より冗長ではありません
CompletableFuture parser = CompletableFuture.supplyAsync(() -> "1")
.thenApply(Integer::parseInt)
.exceptionally(t -> {
t.printStackTrace();
return 0;
}).thenAcceptAsync(s -> System.out.println("CORRECT value: " + s));
3。 whenComplete
Methodの使用-これを使用すると、そのトラックでメソッドが停止し、次のthenAcceptAsync
は実行されません
CompletableFuture correctHandler2 = CompletableFuture.supplyAsync(() -> "A")
.thenApply(Integer::parseInt)
.whenComplete((result, ex) -> {
if (null != ex) {
ex.printStackTrace();
}
})
.thenAcceptAsync(s -> {
System.out.println("When Complete: " + s);
});
4。 completeExceptionally
を介した例外の伝播
public static CompletableFuture<Integer> converter(String convertMe) {
CompletableFuture<Integer> future = new CompletableFuture<>();
try {
future.complete(Integer.parseInt(convertMe));
} catch (Exception ex) {
future.completeExceptionally(ex);
}
return future;
}
あなたはそれをRuntimeException
にラップして投げるべきだと思う:
throw new RuntimeException(ex);
または、多くの小さなユーティリティが役立ちます:
static class Wrapper extends RuntimeException {
private Wrapper(Throwable throwable) {
super(throwable);
}
public static Wrapper wrap(Throwable throwable) {
return new Wrapper(throwable);
}
public Throwable unwrap() {
return getCause();
}
}
public static void go() {
CompletableFuture<String> a = CompletableFuture.supplyAsync(() -> {
try {
throw new Exception("Just because");
} catch (Exception ex) {
throw Wrapper.wrap(ex);
}
});
a.join();
}
そして、unwrap
that ..
try {
go();
} catch (Wrapper w) {
throw w.unwrap();
}
他の人の答えが非常にいい場合でも。しかし、CompletableFuture
でチェック例外をスローする別の方法を提供します。
IF別のスレッドでCompletableFuture
を呼び出したくない場合は、匿名クラスを使用して次のように処理できます。
CompletableFuture<A> a = new CompletableFuture<A>() {{
try {
complete(someObj.someFunc());
} catch (ServerException ex) {
completeExceptionally(ex);
}
}};
IF別のスレッドでCompletableFuture
を呼び出す場合、匿名クラスを使用してそれを処理することもできますが、runAsync
でメソッドを実行します。
CompletableFuture<A> a = new CompletableFuture<A>() {{
CompletableFuture.runAsync(() -> {
try {
complete(someObj.someFunc());
} catch (ServerException ex) {
completeExceptionally(ex);
}
});
}};