调用supplyAsync时尝试并捕获

问题描述 投票:2回答:2

我是CompletableFuture的新手,我想调用MetadataLoginUtil :: login方法,它可以抛出异常。但是,尽管我已经“特别”编写,但下面的代码并未编译。它说我必须在try&catch中包装MetadataLoginUtil :: login'。

请指教。谢谢!

public void run() throws ConnectionException {
    CompletableFuture<Void> mt = CompletableFuture.supplyAsync(MetadataLoginUtil::login)
            .exceptionally(e -> {
                System.out.println(e);
                return null;
            })
            .thenAccept(e -> System.out.println(e));
}
java java-8 completable-future
2个回答
1
投票

CompletableFuture.supplyAsync(Supplier<U>)期望java.util.function.Supplier<U>实例,而Supplier.get()方法的签名不允许检查异常。要清楚地看到这一点,请注意CompletableFuture.supplyAsync(MetadataLoginUtil::login)相当于

CompletableFuture<Void> mt = CompletableFuture.supplyAsync(new Supplier<Void>() {
        @Override
        public Void get() {
            return MetadataLoginUtil.login();
        }
    })

这显然无法编译。

您可以在Supplier中处理异常,将CompletableFuture.supplyAsync(MetadataLoginUtil::login).exceptionally(e -> {System.out.println(e); return null; } )更改为

CompletableFuture.supplyAsync(() -> {
        try {
            return MetadataLoginUtil.login();
        } catch (Exception e) {
            System.out.println(e);
            return null;
        }
    })

它并不漂亮,但CompletableFuture的API似乎不能很好地处理已检查的异常。


7
投票

这不是CompletableFuture一般工作方式的缺陷,而是方便方法的缺陷,都使用不允许检查异常的功能接口。您可以使用另一种supplyAsync方法解决此问题:

public static <T> CompletableFuture<T> supplyAsync(Callable<T> c) {
    CompletableFuture<T> f=new CompletableFuture<>();
    CompletableFuture.runAsync(() -> {
        try { f.complete(c.call()); } catch(Throwable t) { f.completeExceptionally(t); }
    });
    return f;
}

这基本上与原始的supplyAsync相同,但允许检查异常。因此,您可以像在原始尝试中一样使用它,只重定向最初的supplyAsync调用。

CompletableFuture<Void> mt = supplyAsync(MetadataLoginUtil::login)
    .exceptionally(e -> { System.out.println(e); return null; } )
    .thenAccept(e -> System.out.println(e));
© www.soinside.com 2019 - 2024. All rights reserved.