Future만으론 작업을 이어서 수행하는 것이 어려웠다.
// day가 끝나고 dream를 불러오려면 두 번의 get 호출이 이어져야 했다.
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<String> hello = CompletableFuture.supplyAsync(() -> {
System.out.println("day " + Thread.currentThread().getName());
return "day ";
});
CompletableFuture<String> world = CompletableFuture.supplyAsync(() -> {
System.out.println("dream " + Thread.currentThread().getName());
return "dream ";
});
String res1 = hello.get();
String res2 = world.get();
System.out.println(res1 + res2);
}
// day ForkJoinPool.commonPool-worker-19
// dream ForkJoinPool.commonPool-worker-5
// day dream
CompletableFuture의 thenCompose를 사용하면 연관관계가 있는 비동기 작업을 이어서 수행할 수 있다.
thenCompose는 두 작업 간의 의존성이 필요할 때 사용된다.
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<String> daydream = CompletableFuture.supplyAsync(() -> {
System.out.println("day " + Thread.currentThread().getName());
return "day";
}).thenCompose(s -> CompletableFuture.supplyAsync(() -> s + "dream"));
System.out.println(daydream.get());
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<String> hello = CompletableFuture.supplyAsync(() -> {
System.out.println("one " + Thread.currentThread().getName());
return "one";
});
CompletableFuture<String> world = CompletableFuture.supplyAsync(() -> {
System.out.println("two " + Thread.currentThread().getName());
return "two";
});
CompletableFuture<String> onetwo = hello.thenCombine(world, (o, t) -> o + t);
System.out.println(onetwo.get());
}
allOf로 조합한 작업의 결과는 항상 void를 반환
만약 각 작업의 결과를 반환받고 싶다면 futures의 stream을 열어 결괏값을 List<Object>로 받을 수 있다.
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<String> daydream = CompletableFuture.supplyAsync(() -> {
return "daydream";
});
CompletableFuture<Void> empty = CompletableFuture.runAsync(() -> {
});
CompletableFuture<Integer> one = CompletableFuture.supplyAsync(() -> {
return 1;
});
CompletableFuture[] futuresArray = {daydream, empty, one};
List<CompletableFuture> futures = Arrays.asList(futuresArray);
CompletableFuture<List<Object>> results = CompletableFuture.allOf(futuresArray).thenApply(v -> {
return futures.stream()
.map(o -> o.join()) // ignore unchecked exception
.collect(Collectors.toList());
});
results.get().forEach(System.out::println);
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
CompletableFuture<String> daydream = CompletableFuture.supplyAsync(() -> {
return "daydream";
});
CompletableFuture<Integer> blog = CompletableFuture.supplyAsync(() -> {
return 2;
});
CompletableFuture<Object> future = CompletableFuture.anyOf(daydream, blog);
System.out.println(future.get());
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
boolean throwError = true;
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (throwError) throw new IllegalArgumentException();
System.out.println(Thread.currentThread().getName());
return "daydream";
}).exceptionally(e -> "error!");
System.out.println(future.get());
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
boolean throwError = true;
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (throwError) throw new IllegalArgumentException();
System.out.println(Thread.currentThread().getName());
return "daydream";
}).handle((result, ex) -> {
if (ex != null) return "error!";
return result;
});
System.out.println(future.get());
}