需要确认一些事情。以下代码:
CompletableFuture
.supplyAsync(() -> {return doSomethingAndReturnA();})
.thenApply(a -> convertToB(a));
与:
相同CompletableFuture
.supplyAsync(() -> {
A a = doSomethingAndReturnA();
convertToB(a);
});
右?
此外,关于"的另外两个问题是我们有什么理由使用thenApply
?"
1)拥有大量的转换代码?
或
2)需要在其他地方重用lambda块吗?
答案 0 :(得分:54)
不是同一件事。在未使用thenApply
的第二个示例中,确定对convertToB
的调用在与方法doSomethingAndReturnA
相同的线程中执行。
但是,在使用thenApply
方法的第一个例子中,可能会发生其他事情。
首先,如果执行CompletableFuture
的{{1}}已完成,则doSomethingAndReturnA
的调用将在调用者线程中发生。如果thenApply
尚未完成,则会在与CompletableFutures
相同的帖子中调用传递给Function
的{{1}}。
混淆?那么this article might be helpful(感谢@SotiriosDelimanolis的链接)。
我提供了一个简短的示例,说明了thenApply
的工作原理。
doSomethingAndReturnA
输出是:
thenApply
因此,当第一个操作很慢时(即public class CompletableTest {
public static void main(String... args) throws ExecutionException, InterruptedException {
final CompletableFuture<Integer> future = CompletableFuture
.supplyAsync(() -> doSomethingAndReturnA())
.thenApply(a -> convertToB(a));
future.get();
}
private static int convertToB(final String a) {
System.out.println("convertToB: " + Thread.currentThread().getName());
return Integer.parseInt(a);
}
private static String doSomethingAndReturnA() {
System.out.println("doSomethingAndReturnA: " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "1";
}
}
尚未完成),两个调用都发生在同一个线程中。但是如果我们要删除doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1
convertToB: ForkJoinPool.commonPool-worker-1
- 来自CompletableFuture
的调用,则输出(可能)就像这样:
Thread.sleep
请注意,doSomethingAndReturnA
调用位于doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1
convertToB: main
主题。
答案 1 :(得分:2)
thenApply()
是一个回调函数,将在supplyAsync()
返回值时执行。
在代码片段2中,调用doSomethingAndReturnA()
的线程等待函数执行并返回数据。
但在某些特殊情况下(比如进行Webservice调用和等待响应),线程必须等待 long 时间才能获得响应,这会严重占用大量系统计算资源(只需等待回应)。
为避免这种情况,CompletableFuture
附带回调功能,一旦调用doSomethingAndReturnA()
,一个单独的线程将负责执行doSomethingAndReturnA()
和主调用程序线程将继续执行其他操作,而无需等待响应返回。
一旦doSomethingAndReturnA
的响应可用,将调用回调方法(即thenApply()
)