【问题标题】:How to DRY exception handling with Java 8 CompletableFuture when code throws exception?当代码抛出异常时,如何使用 Java 8 CompletableFuture 进行 DRY 异常处理?
【发布时间】:2018-06-19 19:31:32
【问题描述】:

我不了解你们,但是对我来说,当我看到一段代码 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 相对于supplyAsync lambda 内的exception handling

【问题讨论】:

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


    【解决方案1】:

    只需在你的类中添加一个方法来处理所有重复的代码,并将Consumer&lt;List&lt;?&gt;&gt; 作为参数传递给最后一行的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 } );
    

    【讨论】:

    • 我喜欢消费者的想法。
    【解决方案2】:

    模式 用于处理效果,例如函数式编程失败。一种这样的模式是 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&lt;T&gt; 的结果是Try&lt;T&gt;,它可以是Success&lt;T&gt;Failure,您可以相应地处理。

    【讨论】:

    • 我更喜欢CompletableFuture,因为与Future相比,它的阶段和功能不同。不过我不知道vavr,谢谢分享。我将看看vavr 如何融入我正在从事的项目中。
    • @Raf 其实你可以在vavr上调用toCompletableFuture()Future
    【解决方案3】:

    我并不是说这是唯一的方法或最有效的方法,我正在分享对我有帮助的解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-19
      • 2017-03-28
      • 2013-07-24
      • 2017-11-08
      • 1970-01-01
      • 2012-03-30
      • 2021-10-21
      • 1970-01-01
      相关资源
      最近更新 更多