当前位置: 首页 > 知识库问答 >
问题:

如何将代码转换为使用可完成未来?

林祯
2023-03-14

我以前有个可打电话的课

class SampleTask implements Callable<Double> {
  @Override
  public Double call() throws Exception {
    return 0d;
  }
}

我曾经使用ExecutorService提交可调用。如何更改为使用CompletableFuture.supplyAsync?

以下代码无法编译

SampleTask task = new SampleTask();
CompletableFuture.supplyAsync(task);

不存在变量U类型的实例,因此SampleTask符合供应商


共有3个答案

巫化
2023-03-14

由于完整未来::供应同步期望供应商

Callable<Double> task = new SampleTask();
CompletableFuture.supplyAsync(() -> {
  try {
    return task.call();
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
});

刘博雅
2023-03-14

< code>supplyAsync()需要一个< code >供应商

错误消息告诉您编译器已尝试查找用于U的类型,因此您的SampleTask"是"供应商

Java将隐式地将lambda“提升”为功能接口,例如CallableSupplier。但它不会将功能接口视为可互换的——也就是说,不能在需要供应商的地方使用Callable

您可以就地制作合适的λ:

SimpleTask task = new SimpleTask();
CompletableFuture.supplyAsync(() -> task.call());

请注意,如果SimpleTaskcall():

 public Double call() {  // note no exception declared
    return 0d;   
 }

< code>SimpleTask恰好实现< code>Callable这一事实与上面的代码无关。

如果您希望它与任意的< code >可调用一起工作,或者如果您将< code>task声明为< code >可调用:

Callable callable = new SimpleTask();
CompletableFuture.supplyAsync(() -> callable.call());

...然后,您将收到有关未捕获异常的编译器错误。您的 lambda 需要捕获异常并对其进行处理(可能作为未经检查的异常重新引发,如其他答案中所述)。

或者您可以让< code>SampleTask实现< code>Supplier

lambdas的部分动机是写像可调用这样的东西太冗长了。因此,您可能会省略中间类,直接转到:

CompleteableFuture<Double> future = CompletableFuture.supplyAsync(() -> 0d);

这也适用于更复杂的供应商:

CompleteableFuture<Double> future = CompletableFuture.supplyAsync(() -> {
     Foo foo = slowQuery();
     return transformToDouble(foo);
});
艾浩穰
2023-03-14
匿名用户

对于你所写的可调用,你可以简单地使用可完成未来.supply异步(() -

但是,如果您有一个现有的< code>Callable,那么将它与< code>CompletableFuture一起使用就不那么直接了,因为Callable可能会引发检查过的异常。

您可以使用临时供应商来捕获异常并将其包装在未检查的异常中重新抛出,如

CompletableFuture.supplyAsync(() -> {
    try { return callable.call(); }
    catch(Exception e) { throw new CompletionException(e); }
})

使用特定类型< code>CompletionException而不是< code>RuntimeException的任意子类型,可以避免在调用< code>join()时获得包装实际异常的< code>CompletionException包装运行时异常。

不过,在将异常处理程序链接到CompletableFuture时,您会注意到包装。此外,join()抛出的CompletionException子句中创建的,因此包含一些后台线程的堆栈跟踪,而不是调用0.05的线程。换句话说,该行为仍然不同于抛出异常的供应商

使用稍微复杂一点的

public static <R> CompletableFuture<R> callAsync(Callable<R> callable) {
    CompletableFuture<R> cf = new CompletableFuture<>();
    CompletableFuture.runAsync(() -> {
        try { cf.complete(callable.call()); }
        catch(Throwable ex) { cf.completeExceptionally(ex); }
    });
    return cf;
}

你会得到一个可完成的未来,它的行为与supplyAsync完全相同,没有其他包装器异常类型,即如果你使用

callAsync(task).exceptionally(t -> {
    t.printStackTrace();
    return 42.0;
})

< code>t将是由< code>Callable引发的确切异常,即使它是已检查的异常。也就是< code>callAsync(task)。join()将生成一个< code>CompletionException,其中包含< code>join()调用方的堆栈跟踪,直接包装由< code>Callable在异常情况下引发的异常,就像< code>Supplier或< code>runAsync一样。

 类似资料:
  • 我目前正在python中使用Google Vision API检测图像中的汉字,但我发现Google将返回python源代码(如\XE7\X80\X86\XE7\XAB\X91),而不是一些人类可读字符串。 我如何将它转换成utf-8格式的人类可读文本? Requests.Exceptions.ConnectionError除外:打印(“Request Error”) 谢谢你

  • 我有一个实例列表。 如何将他们转变成这样一个未来:

  • 我正在努力在我的项目中获得一个返回200个答案的邮政请求。我们有一个邮递员测试,运行良好,并生成以下代码:

  • 这是我试图转换成java的代码,但我不理解它,实际上我得到这段代码作为一个答案,但他/她用kotlin给我

  • 问题内容: 我刚刚开始使用Java 8,并且正在使用以下代码片段: 如何将其转换为Lambda样式? 问题答案: 如果是 功能界面 ,则可以 这是您问题中其他类的存根实现的完整示例:

  • 问题内容: 我正在将Java库移植到C#。我使用的是Visual Studio 2008,因此没有停止使用的Microsoft Java语言转换助手程序(JLCA)。 我的方法是创建一个与Java库具有类似项目结构的新解决方案,然后将Java代码复制到ac#文件中,并将其逐行转换为有效的c#。考虑到我觉得Java易于阅读,两种语言之间的细微差别使我感到惊讶。 有些事情很容易移植(命名空间,继承等)