CompletableFuture 为异常撰写
CompletableFuture compose for exceptions
CompletableFuture
API 允许我们使用 thenCompose
链接另一个未来:
CompletableFuture<String> future1 = submit("foo");
CompletableFuture<String> future2 = future.thenCompose((result) -> submit(result));
不过这只适用于成功的回复。有没有办法做到同样的同时还包括异常处理?
例如:
CompletableFuture<String> future1 = submit("foo");
CompletableFuture<String> future2 = future.handleCompose((result, error) -> {
if (error != null)
return submit("failure"); // Handle error by doing a different action with the same result (like a fallback)
else
return submit(result);
});
我知道你可以做类似 whenComplete
:
CompletableFuture<String> future2 = new CompletableFuture<>();
CompletableFuture<String> future1 = submit("foo");
future.whenComplete((result, error) -> {
CompletableFuture<String> tmp;
if (error != null)
tmp = submit("failure");
else
tmp = submit(result);
tmp.whenComplete((result2, error2) -> {
if (error2 != null) future2.completeExceptionally(error2);
else future2.complete(result2);
});
});
然而,这失去了正确取消的能力,与成功的组合处理相比,这似乎是一个非常 "hacky" 的解决方案。有没有不需要自己扩展 CompletableFuture 的好方法 class?
问题是我需要从我的方法中 return 一个未来,它应该能够在任何时间点取消整个过程。
您可以组合返回 CompletableFuture
的 handle()
和 thenCompose(x -> x)
:
CompletableFuture<String> future2 = future.handle((result, error) -> {
if (error != null)
return submit("failure"); // Handle error by doing a different action with the same result (like a fallback)
else
return submit(result);
})
.thenCompose(x -> x);
不幸的是,没有办法避免最后的 thenCompose()
。另见 How to avoid invoking CompletableFuture.thenCompose(x -> x)
? 和我对此的评论。
编辑:对于 Java 12+,现在有 exceptionallyCompose()
,我将其描述为 。
您可以使用CompletableFuture.allOf(..),这不是唯一的解决方案,但更好。
public CompletableFuture<String> getSomeDataFromExternalIfPossible() {
var input = "SomeKey";
CompletableFuture<String> externalDataFetchCFuture = getDataFromExternal(input);
return CompletableFuture.allOf(externalDataFetchCFuture)
.exceptionally(
ex -> {
// This exceptionally(...) is required as allOf(...) propagates exception thrown by any of the supplied futures
// Log if you are interested in failed case of externalDataFetchCFuture
return null;
})
.thenCompose(
unused -> {
// Check if externalDataFetchCFuture completed successfully and invoke other Async method if not
if (!externalDataFetchCFuture.isCompletedExceptionally()) {
// On externalDataFetchCFuture successful execution
return externalDataFetchCFuture;
} else {
// On externalDataFetchCFuture failed execution
// Fetching data from DB or from any other integration
return getDataFromExternal2(input);
}
});
}
private CompletableFuture<String> getDataFromExternal(String input) {
return CompletableFuture.completedFuture("abc");
}
private CompletableFuture<String> getDataFromExternal2(String input) {
return CompletableFuture.completedFuture("xyz");
}
CompletableFuture
API 允许我们使用 thenCompose
链接另一个未来:
CompletableFuture<String> future1 = submit("foo");
CompletableFuture<String> future2 = future.thenCompose((result) -> submit(result));
不过这只适用于成功的回复。有没有办法做到同样的同时还包括异常处理?
例如:
CompletableFuture<String> future1 = submit("foo");
CompletableFuture<String> future2 = future.handleCompose((result, error) -> {
if (error != null)
return submit("failure"); // Handle error by doing a different action with the same result (like a fallback)
else
return submit(result);
});
我知道你可以做类似 whenComplete
:
CompletableFuture<String> future2 = new CompletableFuture<>();
CompletableFuture<String> future1 = submit("foo");
future.whenComplete((result, error) -> {
CompletableFuture<String> tmp;
if (error != null)
tmp = submit("failure");
else
tmp = submit(result);
tmp.whenComplete((result2, error2) -> {
if (error2 != null) future2.completeExceptionally(error2);
else future2.complete(result2);
});
});
然而,这失去了正确取消的能力,与成功的组合处理相比,这似乎是一个非常 "hacky" 的解决方案。有没有不需要自己扩展 CompletableFuture 的好方法 class?
问题是我需要从我的方法中 return 一个未来,它应该能够在任何时间点取消整个过程。
您可以组合返回 CompletableFuture
的 handle()
和 thenCompose(x -> x)
:
CompletableFuture<String> future2 = future.handle((result, error) -> {
if (error != null)
return submit("failure"); // Handle error by doing a different action with the same result (like a fallback)
else
return submit(result);
})
.thenCompose(x -> x);
不幸的是,没有办法避免最后的 thenCompose()
。另见 How to avoid invoking CompletableFuture.thenCompose(x -> x)
? 和我对此的评论。
编辑:对于 Java 12+,现在有 exceptionallyCompose()
,我将其描述为
您可以使用CompletableFuture.allOf(..),这不是唯一的解决方案,但更好。
public CompletableFuture<String> getSomeDataFromExternalIfPossible() {
var input = "SomeKey";
CompletableFuture<String> externalDataFetchCFuture = getDataFromExternal(input);
return CompletableFuture.allOf(externalDataFetchCFuture)
.exceptionally(
ex -> {
// This exceptionally(...) is required as allOf(...) propagates exception thrown by any of the supplied futures
// Log if you are interested in failed case of externalDataFetchCFuture
return null;
})
.thenCompose(
unused -> {
// Check if externalDataFetchCFuture completed successfully and invoke other Async method if not
if (!externalDataFetchCFuture.isCompletedExceptionally()) {
// On externalDataFetchCFuture successful execution
return externalDataFetchCFuture;
} else {
// On externalDataFetchCFuture failed execution
// Fetching data from DB or from any other integration
return getDataFromExternal2(input);
}
});
}
private CompletableFuture<String> getDataFromExternal(String input) {
return CompletableFuture.completedFuture("abc");
}
private CompletableFuture<String> getDataFromExternal2(String input) {
return CompletableFuture.completedFuture("xyz");
}