JavahandleAsync不會處理不是來自完成階段的例外,例如:
package my.package;
import java.util.concurrent.CompletableFuture;
public class Test {
private CompletableFuture<String> throwWithoutCompletionStage() {
throw new RuntimeException("error");
}
private CompletableFuture<String> getName() {
// calls external API, does some work then throws
throwWithoutCompletionStage();
return CompletableFuture.completedFuture("name");
}
public CompletableFuture<String> process() {
return getName()
.thenApplyAsync(result -> {
// do something
return result;
})
.handleAsync((result, exception) -> {
if (exception != null) {
return result;
} else {
return null;
}
});
}
}
When processis calledhandleAsync不會執行,而是將例外傳播給process's 呼叫者,這有點令人困惑,因為人們會認為這handleAsync會捕獲例外。所以在這種情況下,我還需要包裝process在 try/catch 中以真正捕獲所有在我看來看起來很奇怪并且容易出錯的例外:我們需要始終記住包裝CompletableFuture在兩者中回傳的方法handleAsync和 try/catch。
是否有防止這種雙重例外捕獲的最佳實踐?我想到的一種解決方案是呼叫supplyAsyncwhich 將創建一個完成階段,然后handleAsync在其上使用:
public CompletableFuture<CompletableFuture<String>> process() {
return CompletableFuture.supplyAsync(() -> getName())
.handleAsync((result, exception) -> {
if (exception != null) {
return null;
} else {
return result;
}
});
}
這段代碼的問題在于,現在process回傳型別是CompletableFuture<CompletableFuture<String>>,而且這似乎是多余的,supplyAsync僅為了handleAsync捕獲所有例外而將代碼包裝起來。
uj5u.com熱心網友回復:
如果你不想改變getName()方法的行為,你必須使用類似的東西
public CompletableFuture<String> process() {
return CompletableFuture.supplyAsync(this::getName, Runnable::run)
.thenCompose(Function.identity())
.thenApplyAsync(result -> {
// do something
return result;
})
.handleAsync((result, exception) -> {
if (exception != null) {
return result;
} else {
return null;
}
});
}
通過使用Runnable::runasExecutor可以確保在呼叫者執行緒中立即執行“異步”操作,就像直接呼叫 ofgetName()一樣。使用.thenCompose(Function.identity()),您可以CompletableFuture<String>擺脫CompletableFuture<CompletableFuture<String>>.
但是,如果getName()在成功的情況下回傳一個完整的未來,它也應該在例外情況下回傳一個未來。這可能看起來像
private CompletableFuture<String> getName() {
try {
throwWithoutCompletionStage();
return CompletableFuture.completedFuture("name");
} catch(Throwable t) {
return CompletableFuture.failedFuture(t);
}
}
failedFuture在 Java 9 中已經引入。如果您需要兼容 Java 8 的解決方案,則必須將這樣的工廠方法添加到您的代碼庫中
public static <U> CompletableFuture<U> failedFuture(Throwable ex) {
CompletableFuture<U> f = new CompletableFuture<>();
f.completeExceptionally(ex);
return f;
}
或者您將此邏輯集成到getName()方法中:
private CompletableFuture<String> getName() {
CompletableFuture<String> result = new CompletableFuture<>();
try {
throwWithoutCompletionStage();
result.complete("name");
} catch(Throwable t) {
result.completeExceptionally(t);
}
return result;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/512943.html
標籤:爪哇异步例外可完成的未来
