代码抛出异常时,如何使用Java 8 CompletableFuture进行异常处理?

时间:2018-06-19 19:31:33

标签: java java-8 future dry completable-future

我不了解你们,但是对我来说,当我看到一段repeated的代码,并且在使用Services并抛出异常时遇到了以下情况。如下所示,在每个CompletableFuture块中,我都必须做exception handling,该部分基本上会重复执行,具体取决于您将要拥有多少个可完成的期货。

CompletableFuture<Void> future1Of15 = CompletableFuture.supplyAsync(() -> {
    List<SomePojo> somePojos = null;
    try {
        somePojos = someServiceThatThrowsException.getAll(SomePojo.class);
    } catch (SomeException e) {
       //Handle the exception
       e.printStackTrace();
    } 
    return somePojos; 
}).thenAcceptAsync(result -> //do something with the result); 

CompletableFuture<Void> future2Of15 = CompletableFuture.supplyAsync(() -> {
    List<OtherPojo> otherPojos = null;
    try {
        otherPojos = someServiceThatThrowsException.getAll(OtherPojo.class);
    } catch (SomeException e) {
           //Handle the exception
           e.printStackTrace();
    } 
    return otherPojos; 
}).thenAcceptAsync(result -> //do something with the result); 

现在重复上述x的次数,您会注意到try/catch块已重复。就我而言,我大约有15-20个这样的电话。

是否可以将上面的代码转换为1或2行代码?在stop repeating myself内相对于exception handling而言,supplyAsync lambda的顺序是什么?

3 个答案:

答案 0 :(得分:2)

只需向您的类添加一个执行所有重复代码的方法,并以Consumer<List<?>>作为参数传递给最后一行的thenAcceptAsync

private CompletableFuture<Void> getAndAcceptAsync(Consumer<List<?>> resultProcessor) {  
    return CompletableFuture.supplyAsync(() -> {
        List<SomePojo> somePojos = null;
        try {
            somePojos = someServiceThatThrowsException.getAll(SomePojo.class);
        } catch (SomeException e) {
           //Handle the exception
           e.printStackTrace();
        } 
        return somePojos; 
    }).thenAcceptAsync(resultProcessor);
}

然后您可以根据需要多次拨打此电话。

future1Of15 = getAndAcceptAsync(result-> { do something } );
future2Of15 = getAndAcceptAsync(result-> { do something else } );

答案 1 :(得分:2)

patterns 用于处理诸如功能编程失败。一种这样的模式是Try monad,例如vavr提供了Java实现。

这些模式通过声明性的api将很多样板从您身上抽象出来:

CompletableFuture
    .supplyAsync(() -> Try.of(() -> methodThatThrows()))
    .thenAccept(res -> System.out.println(res));

或者,如果您不打算使用CompletableFuture,则可以选择使用Future monad进一步减少样板代码:

Future.of(() -> methodThatThrows())
    .onComplete(result -> System.out.println(result));

无论哪种方式,最终得到的Future<T>都是Try<T>,可以是Success<T>Failure都可以处理相应地。

答案 2 :(得分:0)

我并不是说这是唯一的方法,还是最有效的方法,我是在分享对我DRY有帮助的解决方案,它可能会也可能不会为您服务。如果您有更好的解决方案,请分享。

我创建了以下实用程序方法

@Component
public class CompletableFutureUtil {
    @Autowired
    private SomeGenericServiceThatThrowsException genericService; 

    public <T> CompletableFuture<Collection<T>> fireupCompletableFutureAsynchronously(Class<T> type) {
        CompletableFuture<Collection<T>> future = CompletableFuture.supplyAsync(() -> {
            Collection<T> mystery = null;
            try {
                mystery = genericService.list(type); 
            } catch (SomeException e) {
                e.printStackTrace(); 
                //Handle the exception
            } 
            return mystery; 
        }); 
        return future; 
    }
}

现在,autowiring之后,我可以按以下方式重用上述实用程序方法

@Autowired private CompletableFutureUtil futureUtil;

通话基本上最多变成一到两行

futureUtil.fireupCompletableFutureAsynchronously(SomePojo.class)
                .thenAcceptAsync(result -> //do something with result); 

futureUtil.fireupCompletableFutureAsynchronously(OtherPojo.class)
                .thenAcceptAsync(result -> //do something with result);

开心的DRY+ing

相关问题