使用CompletableFuture处理Java 8供应商异常

ayu*_*ush 7 java exception java-8 completable-future

考虑以下代码 -

public class TestCompletableFuture {

    BiConsumer<Integer, Throwable> biConsumer = (x,y) -> {
        System.out.println(x);
        System.out.println(y);
    };

    public static void main(String args[]) {
        TestCompletableFuture testF = new TestCompletableFuture();
        testF.start();      
    }

    public void start() {
        Supplier<Integer> numberSupplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                return SupplyNumbers.sendNumbers();                     
            }
        };
        CompletableFuture<Integer> testFuture = CompletableFuture.supplyAsync(numberSupplier).whenComplete(biConsumer);         
    }       
}

class SupplyNumbers {
    public static Integer sendNumbers(){
        return 25; // just for working sake its not  correct.
    }
}
Run Code Online (Sandbox Code Playgroud)

以上的事情很好.但是sendNumbers也可以在我的情况下抛出一个检查过的异常,例如:

class SupplyNumbers {
    public static Integer sendNumbers() throws Exception {
        return 25; // just for working sake its not  correct.
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我想y在我的处理中处理这个异常biConsumer.这将帮助我在单个函数(biConsumer)中处理结果以及异常(如果有的话).

有任何想法吗?我可以CompletableFuture.exceptionally(fn)在这里或其他什么地方使用?

Hol*_*ger 16

当您想要处理已检查的异常时,使用标准功能接口的工厂方法没有帮助.当您将代码捕获到lambda表达式中时,您遇到的问题是catch子句需要CompletableFuture实例来设置异常,而工厂方法需要Supplier,鸡和蛋.

您可以使用类的实例字段在创建后允许变异,但最终,生成的代码不是干净的,而且比Executor基于直接的解决方案更复杂.该文件CompletableFuture说:

所以你知道以下代码将显示CompletableFuture.supplyAsync(Supplier)直接处理检查异常时的标准行为:

CompletableFuture<Integer> f=new CompletableFuture<>();
ForkJoinPool.commonPool().submit(()-> {
  try { f.complete(SupplyNumbers.sendNumbers()); }
  catch(Exception ex) { f.completeExceptionally(ex); }
});
Run Code Online (Sandbox Code Playgroud)

文件还说:

...为了简化监视,调试和跟踪,所有生成的异步任务都是标记接口的实例CompletableFuture.AsynchronousCompletionTask.

如果您希望遵循此约定以使解决方案更像原始supplyAsync方法,请将代码更改为:

CompletableFuture<Integer> f=new CompletableFuture<>();
ForkJoinPool.commonPool().submit(
  (Runnable&CompletableFuture.AsynchronousCompletionTask)()-> {
    try { f.complete(SupplyNumbers.sendNumbers()); }
    catch(Exception ex) { f.completeExceptionally(ex); }
});
Run Code Online (Sandbox Code Playgroud)

  • @Jasonw:这是*交叉型*的演员.换句话说,该对象必须实现两种类型,`Runnable`*和*CompletableFuture.AsynchronousCompletionTask`.由于类型转换为lambda表达式提供了上下文类型,这意味着生成的lambda实例将实现两个接口.另见[here](http://stackoverflow.com/a/22808112/2711488) (3认同)

ass*_*ias 7

你已经抓住了这个例外y.也许你没有看到它因为main在CompletableFuture有机会完成之前退出了?

下面的代码按预期打印"null"和"Hello":

public static void main(String args[]) throws InterruptedException {
  TestCompletableFuture testF = new TestCompletableFuture();
  testF.start();
  Thread.sleep(1000); //wait for the CompletableFuture to complete
}

public static class TestCompletableFuture {
  BiConsumer<Integer, Throwable> biConsumer = (x, y) -> {
    System.out.println(x);
    System.out.println(y);
  };
  public void start() {
    CompletableFuture.supplyAsync(SupplyNumbers::sendNumbers)
            .whenComplete(biConsumer);
  }
}

static class SupplyNumbers {
  public static Integer sendNumbers() {
    throw new RuntimeException("Hello");
  }
}
Run Code Online (Sandbox Code Playgroud)


die*_*ter 2

也许您可以使用 new Object 来包装您的整数和错误,如下所示:

public class Result {

    private Integer   integer;
    private Exception exception;

    // getter setter

}
Run Code Online (Sandbox Code Playgroud)

进而:

public void start(){
    Supplier<Result> numberSupplier = new Supplier<Result>() {
        @Override
        public Result get() {
            Result r = new Result();
            try {
                r.setInteger(SupplyNumbers.sendNumbers());
            } catch (Exception e){
                r.setException(e);
            }
            return r;

        }
    };
    CompletableFuture<Result> testFuture = CompletableFuture.supplyAsync(numberSupplier).whenComplete(biConsumer);
}
Run Code Online (Sandbox Code Playgroud)