CompletableFuture诞生于Java 8,是对Future的一种改进,由于使用Future会造成回调地狱,所以CompletableFuture应运而生。CompletableFuture是对Future的一种扩展,可以通过设置回调的方式处理计算结果,同时支持组合操作,一定程度解决了回调地狱的问题。

基本使用

supplyAsync

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static void main(String[] args) {
System.out.println();
System.out.println(Thread.currentThread().getName() + "冰红茶进入教室");
System.out.println(Thread.currentThread().getName() + "冰红茶坐在座位上");

CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "老师正在走到教室");
System.out.println(Thread.currentThread().getName() + "老师到达教室");

return "准备上课!";
});

System.out.println(Thread.currentThread().getName() + "冰红茶正在自习");
System.out.println(String.format(Thread.currentThread().getName() + "%s 冰红茶开始听讲", cf.join()));
}

suppluAsync的传入参数是一个函数式接口,返回一个泛型类型的值。在supplyAsync方法中,会创建一个新的线程来执行传入的函数式接口,返回一个CompletableFuture对象。
suppluAsync方法实现了函数重载,如下

1
2
CompletableFuture<Object> supplyAsync(Supplier<Object>)
CompletableFuture<Object> supplyAsync(Supplier<Object>, Executor)

第一个方法会使用ForkJoinPool.commonPool()作为线程池,第二个方法可以传入自定义的线程池。传入的任务就是从线程池中取出一个线程,然后进行执行的。

类似的有runAsync方法,runAsync方法没有返回值。

thenCompose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + "冰红茶进入教室");
System.out.println(Thread.currentThread().getName() + "冰红茶坐在座位上");

CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "老师正在走到教室");
System.out.println(Thread.currentThread().getName() + "老师到达教室");

return "准备上课!";
}).thenCompose(msg -> {
System.out.println("班长准备发言");
return CompletableFuture.supplyAsync(() -> msg + "班长:起立!");
});

System.out.println(Thread.currentThread().getName() + "冰红茶正在自习");
System.out.println(String.format(Thread.currentThread().getName() + "%s 冰红茶开始听讲", cf.join()));
}

thenCompose方法是将两个CompletableFuture进行组合,第一个CompletableFuture的返回值会作为第二个CompletableFuture的入参。thenCompose方法的参数是一个Function函数式接口,返回一个CompletableFuture对象。
还有一个thenComposeAsync方法,和thenCompose差不多,就是异步执行,传入的任务会从线程池中取出一个线程进行执行。

thenCombine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + "冰红茶进入教室");
System.out.println(Thread.currentThread().getName() + "冰红茶坐在座位上");

CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "老师正在走到教室");
System.out.println(Thread.currentThread().getName() + "老师到达教室");

return "准备上课!";
}).thenCombine(CompletableFuture.supplyAsync(() -> {
System.out.println("牢大坐在努力");
return "Man!! What can I say";
}), (msg1, msg2) -> msg1 + msg2);

System.out.println(Thread.currentThread().getName() + "冰红茶正在自习");
System.out.println(String.format(Thread.currentThread().getName() + "%s 冰红茶开始听讲", cf.join()));
}

thenCombine方法是将两个CompletableFuture进行组合,第一个CompletableFuture的返回值和第二个CompletableFuture的返回值会作为入参。通过BiFunction函数式接口来处理前两个CompletableFuture的返回值作为入参,然后返回一个新的值。

类似的有thenAcceptBoth方法,不过thenAcceptBoth方法没有返回值。runAfterBoth方法也是类似的,不过runAfterBoth方法没有返回值,也没有入参。

thenApply

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + "冰红茶进入教室");
System.out.println(Thread.currentThread().getName() + "冰红茶坐在座位上");

CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "老师正在走到教室");
System.out.println(Thread.currentThread().getName() + "老师到达教室");

return "准备上课!";
}).thenApply(msg -> {
System.out.println("班长发言");
return msg + "班长:全体起立!";
});

System.out.println(Thread.currentThread().getName() + "冰红茶正在自习");
System.out.println(String.format(Thread.currentThread().getName() + "%s 冰红茶开始听讲", cf.join()));
}

thenApply方法是将CompletableFuture的返回值作为入参,然后返回一个新的值。thenApply方法的参数是一个Function函数式接口,返回一个新的值。用法和thenCompose差不多,只是thenCompose返回的是一个CompletableFuture对象。

类似的有thenAccept方法,thenAccept方法没有返回值。thenRun方法,没有入参和返回值。

applyToEither

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + "冰红茶进入教室");
System.out.println(Thread.currentThread().getName() + "冰红茶坐在座位上");

CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "老师正在走到教室");
System.out.println(Thread.currentThread().getName() + "老师到达教室");

return "准备上课!";
}).applyToEither(CompletableFuture.supplyAsync(() -> {
System.out.println("牢大来咯");

return "Man!!!What can I say";
}), firstmsg -> firstmsg);

System.out.println(Thread.currentThread().getName() + "冰红茶正在自习");
System.out.println(String.format(Thread.currentThread().getName() + "%s 冰红茶开始听讲", cf.join()));
}

applyToEither方法是将两个CompletableFuture进行组合,返回最快执行完的CompletableFuture的返回值。applyToEither方法的参数是一个CompletableFuture对象,返回一个新的值。

类似的有acceptEither方法,acceptEither方法没有返回值。runAfterEither方法也是类似的,没有入参和返回值。

exceptionally

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName() + "冰红茶进入教室");
System.out.println(Thread.currentThread().getName() + "冰红茶坐在座位上");

CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
System.out.println(Thread.currentThread().getName() + "老师正在走到教室");
System.out.println(Thread.currentThread().getName() + "老师到达教室");
return "准备上课!";
}).applyToEither(CompletableFuture.supplyAsync(() -> {
System.out.println("牢大来咯");
return "Man!!!What can I say";
}), firstmsg -> {
if ("准备上课!".equals(firstmsg)) {
throw new RuntimeException("老师有事了");
}
return firstmsg;
}).exceptionally(e -> {
System.out.println(e.getMessage());
return "这节课自习!";
});

System.out.println(Thread.currentThread().getName() + "冰红茶正在自习");
System.out.println(String.format(Thread.currentThread().getName() + "%s 冰红茶开始听讲", cf.join()));
}

exceptionally方法是处理异常的,如果CompletableFuture执行过程中出现异常,会调用exceptionally方法,返回一个新的值。exceptionally方法的参数是一个Function函数式接口,返回一个新的值。

类似的有handle方法,handle方法也是处理异常的,不过handle方法的参数是一个BiFunction函数式接口(入参为正常执行的结果和异常的结果),返回一个新的值。whenComplete方法也是类似的,入参为正常执行的结果和异常的结果,不过whenComplete方法没有返回值。