Java8 CompletableFuture API一览表
学习完了这篇 Java8 CompletableFuture 用法全解,还是想给繁多的API归个类,于是有了这篇文章。
一、起始方法
首先,runAsync 和 supplyAsync 都是静态方法,因此调用他们可以帮我们创建 CompletableFuture 实例。
静态方法 | 传入任务类型 | 任务参数 | 任务返回值 |
---|---|---|---|
runAsync | Runnable | 无参数 | 无 |
supplyAsync | Supplier | 无参数 | 自定义返回类型 |
二、异步回调
上一个任务(即发起以下方法调用的对象)执行完成后执行的动作,即回调方法,会将上一个任务的执行结果即方法返回值作为入参传递到回调方法中
成员变量方法 | 传入回调方法类型 | 回调方法参数 | 回调方法返回值 | 多个回调方法的开始顺序 |
---|---|---|---|---|
thenApply | Function | 上一任务的执行结果 | 有 | 多个回调顺序执行 |
thenApplyAsync | Function | 上一任务的执行结果 | 有 | 多个回调同时开始 |
thenAccept | Consumer | 上一任务的执行结果 | 无 | 多个回调顺序执行 |
thenAcceptAsync | Consumer | 上一任务的执行结果 | 无 | 多个回调同时开始 |
thenRun | Runnable | 忽略上一任务执行结果 | 无 | 多个回调顺序执行 |
thenRunAsync | Runnable | 忽略上一任务执行结果 | 无 | 多个回调同时开始 |
所谓多个回调顺序执行是指按照主线程调用的先后顺序,依次执行回调函数。前一个回调执行完,后一个回调才开始执行。
以上的几个回调方法,如果执行到某个回调函数时发生异常,将会立即中止执行,在主线程调用 get() 方法的地方,抛出 ExecutionException 执行异常。
如果希望发生异常也要继续执行的话,可以考虑以下几个回调方法。
成员变量方法 | 传入回调方法类型 | 回调方法参数 | 回调方法返回值 | 多个回调方法的开始顺序 |
---|---|---|---|---|
exceptionally | Function | 上一任务的执行出现的异常 | 有 | 多个回调顺序执行 |
handle | BiFunction | 上一任务的执行结果&可能出现的异常 | 有 | 多个回调同时开始 |
handleAsync | BiFunction | 上一任务的执行结果&可能出现的异常 | 有 | 多个回调顺序执行 |
whenComplete | BiConsumer | 上一任务的执行结果&可能出现的异常 | 无 | 多个回调同时开始 |
whenCompleteAsync | BiConsumer | 上一任务的执行结果&可能出现的异常 | 无 | 多个回调顺序执行 |
注意:
- 如果上一个任务没有发生异常,那么 exceptionally 指定的回调函数就不会被执行!!
- 无论上一个任务发生异常还是正常返回,除 exceptionally 外的其他四个回调函数是会正常执行的;
- 如果上一个任务是正常返回,那么除 exceptionally 外的其他四个回调函数的第二个Throwable类型的方法参数,值为 null;
- 如果上一个任务是异常结束的,那么除 exceptionally 外的其他四个回调函数的第一个方法参数,值为 null;
三、组合处理
3.1 两个前置任务与回调函数
只有两个前置任务都正常执行完了,才会执行回调方法。
成员变量方法 | 传入回调方法类型 | 回调方法参数 | 回调方法返回值 | 多个回调方法的开始顺序 |
---|---|---|---|---|
thenCombine | BiFunction | 两个前置任务的执行结果 | 有 | 多个回调顺序执行 |
thenCombineAsync | BiFunction | 两个前置任务的执行结果 | 有 | 多个回调同时开始 |
thenAcceptBoth | BiConsumer | 两个前置任务的执行结果 | 无 | 多个回调顺序执行 |
thenAcceptBothAsync | BiConsumer | 两个前置任务的执行结果 | 无 | 多个回调同时开始 |
runAfterBoth | Runnable | 忽略两个前置任务的执行结果 | 无 | 多个回调顺序执行 |
runAfterBothAsync | Runnable | 忽略两个前置任务的执行结果 | 无 | 多个回调同时开始 |
只要两个前置任务中有一个正常执行完了,就会执行回调方法。
成员变量方法 | 传入回调方法类型 | 回调方法参数 | 回调方法返回值 | 多个回调方法的开始顺序 |
---|---|---|---|---|
applyToEither | Function | 率先完成的前置任务的执行结果 | 有 | 多个回调顺序执行 |
applyToEitherAsync | Function | 率先完成的前置任务的执行结果 | 有 | 多个回调同时开始 |
acceptEither | Consumer | 率先完成的前置任务的执行结果 | 无 | 多个回调顺序执行 |
acceptEitherAsync | Consumer | 率先完成的前置任务的执行结果 | 无 | 多个回调同时开始 |
runAfterEither | Runnable | 忽略前置任务的执行结果 | 无 | 多个回调顺序执行 |
runAfterEitherAsync | Runnable | 忽略前置任务的执行结果 | 无 | 多个回调同时开始 |
3.2 三个及以上任务与回调函数
静态方法 allOf 返回的 CompletableFuture 是多个任务都执行完成后才会执行。
连用方法 | get方法是否总是等待所有任务完成 | 有一个及以上任务发生异常 | 回调函数第一个参数的值 | 回调函数第二个参数(Throwable)的值 | 多个任务发生异常时 |
---|---|---|---|---|---|
whenComplete | 是 | 主线程get方法调用处发生 ExecutionException 异常 | 总是 null | 如果全部任务正常执行,总是null | 只有最早发生的异常会被回调 且其他正常执行的任务都会完整执行 |
handle | 是 | 主线程get方法不会抛出异常,返回回调函数中设定的返回值 | 总是 null | 如果全部任务正常执行,总是null | 同上 |
- 与 whenComplete 连用时,只要有一个任务执行异常,当所有任务都执行完以后,调用 get 方法的地方也会抛出 ExecutionException 异常;
- 与 whenComplete 连用时,如果全部都是正常执行,则 get 方法返回 null。
- 与 whenComplete 连用时,不管所有任务是正常结束还是异常结束,回调方法的第一个参数始终为 null;
- 与 whenComplete 连用时,如果有两个及以上任务执行异常,那么回调函数只会回调最先出现的异常,其他异常不会进入回调函数,但是正常执行的任务仍然会进入回调函数!
- 与 handle 连用时,如果全部都是正常执行,则 get 方法返回的是回调函数的返回值。
- 与 handle 连用时,不管所有任务是正常结束还是异常结束,回调方法的第一个参数始终为 null;
- 与 handle 连用时,只要有一个任务执行异常,那么 get 方法返回的仍然是回调函数的返回值。
- 与 handle 连用时,如果有两个及以上任务执行异常,那么回调函数只会回调最先出现的异常,其他异常不会进入回调函数,但是正常执行的任务仍然会进入回调函数!
静态方法 anyOf 返回的 CompletableFuture :只要有一个任务执行完成,无论是正常执行或者执行异常,立即执行回调。
因此,与 whenComplete 或者 handle 连用时,回调函数的第一个和第二个参数值,都取决于率先完成的任务的返回值或者所抛异常!!
- 如果与 whenComplete 连用,率先执行完成的任务,如果是异常返回,那么主线程 get 方法调用处会抛出 ExecutionException 异常;相反地,与 handle 连用时, get 方法不会抛出异常。
四、嵌套执行
thenCompose 与 thenApply 最大的区别区别就是参数 Function 的返回值类型不同:
public <U> CompletableFuture<U> thenApply(
Function<? super T,? extends U> fn) {
return uniApplyStage(null, fn);
}
public <U> CompletableFuture<U> thenCompose(
Function<? super T, ? extends CompletionStage<U>> fn) {
return uniComposeStage(null, fn);
}
于是就可以嵌套使用 CompletableFuture 了。