CompletableFuture withFallback /只处理一些错误

我通过CompletableFuture收到服务电话的回复。 我想处理服务返回的一些已知exception – 例如乐观并发控制冲突。

这就是我所拥有的。 有没有更好的方法来做这个不包装exception或使用SneakyThrows? 包装exception意味着其他exception处理程序必须检查因果链而不仅仅是使用instanceof

 someService.call(request) .handle((response, error) -> { if (error == null) return CompletableFuture.completedFuture(response); else if (error instanceof OCCException) return CompletableFuture.completedFuture(makeDefaultResponse()); CompletableFuture errorFuture = new CompletableFuture(); errorFuture.completeExceptionally(error); return errorFuture; }).thenCompose(Function.identity()); 

同样的,有没有办法复制番石榴withFallback没有包装解开?

 CompletableFuture withFallback(CompletableFuture future, Function<Throwable, ? extends CompletableFuture> fallback) { return future.handle((response, error) -> { if (error == null) return CompletableFuture.completedFuture(response); else return fallback.apply(error); }).thenCompose(Function.identity()); } ... // Here's the first part of the question implemented using withFallback. // It's a little cleaner, but it still requires wrapping as a future. withFallback(someService.call(request), error -> { if (error instanceof OCCException) return CompletableFuture.completedFuture(makeDefaultResponse()); CompletableFuture errorFuture = new CompletableFuture(); errorFuture.completeExceptionally(error); return errorFuture; }); 

为了完整性,如果我允许包含exception,这就是它的样子。 (我有一个unit testing来validation抛出的exception在链中传播):

 someService.call(request) .exceptionally(error -> { if (error instanceof OCCException) return makeDefaultResponse(); else // wrap because error is declared as a checked exception throw new RuntimeException(error); }); 

您要求的番石榴风格function可以像这样实现:

 static  CompletableFuture withFallback(CompletableFuture future, Function> fallback) { return future.handle((response, error) -> error) .thenCompose(error -> error!=null? fallback.apply(error): future); } 

通过重复使用源代码未来,我们不希望进行任何转换,从而更加紧凑并节省资源。 但是为了让调用者有机会在不引入另一个辅助方法的情况下做同样的事情,更改方法并使用BiFunction非常有用,它将源未来作为附加参数:

 static  CompletableFuture withFallback(CompletableFuture future, BiFunction, Throwable, ? extends CompletableFuture> fallback) { return future.handle((response, error) -> error) .thenCompose(error -> error!=null? fallback.apply(future,error): future); } 

然后你可以像这样使用它:

 withFallback(someService.call(request), (f,t) -> t instanceof OCCException? CompletableFuture.completedFuture(makeDefaultResponse()): f) 

我能想到的唯一方法是定义一个这样的辅助方法:

 static  CompletableFuture betterHandle(CompletableFuture source, Class excClass, Supplier sup) { CompletableFuture result = new CompletableFuture<>(); source.whenComplete( (t, ex) -> { if (ex == null) { result.complete(t); } else if (excClass.isInstance(ex)) { result.complete(sup.get()); } else { result.completeExceptionally(ex); } }); return result; } 

它不漂亮,但它可以让你避免包装exception:

 CompletableFuture<...> result = betterHandle( someService.call(request), OCCException.class, () -> makeDefaultResponse() );