Ответ 1
Это не одно и то же. Во втором примере, когда thenApply
не используется, уверен, что вызов convertToB
выполняется в том же потоке, что и метод doSomethingAndReturnA
.
Но в первом примере, когда используется метод thenApply
, могут случиться другие вещи.
Прежде всего, если завершен CompletableFuture
, выполняющий doSomethingAndReturnA
, вызов thenApply
произойдет в потоке вызывающего. Если CompletableFutures
не был завершен, Function
, переданный в thenApply
, будет вызываться в том же потоке, что и doSomethingAndReturnA
.
Непонятный? Хорошо эта статья может быть полезна (спасибо @SotiriosDelimanolis за ссылку).
Я привел короткий пример, иллюстрирующий, как работает 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
-call из doSomethingAndReturnA
, то вывод (может быть) следующий:
doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1
convertToB: main
Обратите внимание, что вызов convertToB
находится в потоке main
.