1 概述
仔细看了下 ES6 中的 Promise 的设计理念,感觉不错,本文就将其中的设计理念在 Java 中实现下。
Promise 用于将程序中的 正常处理结果,异常,finally 代码库中的执行封装到 Promise 中并返回,可以避免通过在方法上传入回调函数的方式处理,能够带来如下好处:
- 以优雅的方式对 方法 的返回结果进行处理
- 减少 try…catch…finally 重复代码
- 避免大量的回调函数
- 完美的处理全局异常
- 方便的将方法的 处理结果,异常信息 进行传递以及处理
2 古典的做法
- 古典的做法是一个方法有或者没有返回值,有或者没有参数,抛出异常或者本身进行 try…catch…finally 处理,
其他的方法再对当前的方法进行 try…catch…finally 处理,如果有返回值,再对返回值进行处理
一个普通的方法
1 | public class Person { |
- 古典的处理
1 | @Test |
3 Promise 的做法
Promise 会对 方法的 返回值,方法的异常进行封装,然后:
- 通过 Promise 的 then 方法对 原来的方法返回结果 进行处理
- 通过 Promise 的 thenCatch 方法对 原来的方法的异常 进行处理
- 通过 Promise 的 thenFinally 方法在 原来的方法 执行完毕后(无论有无异常) 进行处理
4 Promise 的 Java 实现
- Promise 类
1 | import java.util.concurrent.Callable; |
- Resolve 接口方法
1 | /** |
- Reject 接口方法
1 | /** |
5 获取 Promise 的4种方法
- 和原来的方法融合,方法直接返回 Promise 对象
- 通过 Promise 的构造方法
public Promise(final Callable<T> callable)
- 通过 Promise 内置的构造器
- 通过 Promise 的静态方法 Of
5.1 方法1:目标方法直接返回 Promise 对象
目标方法直接返回 Promise 对象
1 | /** |
- 输出如下
1 | 处理方法的返回:worktest |
5.2 方法2:通过 Promise 的构造方法返回一个 Promise 对象
通过 Promise 的构造方法返回一个 Promise 对象,构造方法的参数是一个 Callable 对象
1 | /** |
- 输出如下
1 | work:ab |
5.3 方法3:通过 Promise 内置的构造器构造
通过 Promise 内置的构造器构造,原理上和方法2 类似。
1 | /** |
- 输出如下
1 | 对结果的处理方式1:work:test |
5.4 方法4:通过 Promise 的静态方法 Of
1 | @Test |
- 输出如下
1 | 执行完毕 |
注意:如果目标方法的返回值为 null,那么 then 方法其实并没有执行 Resolve 对象的 resolve 方法
6 通过 Promise 完美的处理全局异常
由于 Promise 对象中的 thenCatch 方法可以处理异常,如果系统中需要全局异常处理的方法返回的是 Promise 对象,那么就可以轻松的实现 全局异常 处理。
- MyException 自定义全局异常类如下
1 | /** |
- GlobalExceptionHandler 全局异常处理
1 | import org.slf4j.Logger; |
- 测试如下
1 | /** |
- 输出
1 | 18:57:01.329 [main] ERROR c.c.async.GlobalExceptionHandler - 出现异常 |
7 避免大量的回调函数
如何避免?可以看看现有的做法是怎么样的,以及 Promise 是怎么做的,对比之后一目了既然。
7.1 通过回调函数的方式来处理 方法 的返回值和异常
通过在参数中增加 successConsumer 成功处理的回调,throwableConsumer 异常处理的回调,runnable finally 处理的回调,具体如下
1 | /** |
- 测试
1 | @Test |
- 输出
1 | work result:work |
7.2 回调函数方式的坏处
- 需要修改原来方法的参数
- 如果要增加对方法返回值的处理逻辑,就需要改成
final List<Consumer<String>> successConsumerList
,具体如下
1 | /** |
7.3 如何通过 Promise 来避免大量的回调函数
- 通过 Promise 封装后的方法,再调用 then,thenCatch,thenFinally 方法后返回的仍然是 Promise 对象
- 这就意味着可以重复调用 then,thenCatch,thenFinally 方法,具体如下
1 | @Test |
- 执行如下
1 | 对结果的处理方式1:work:test |
8 使用
引入 xutils 工具包 1.0.9 版本,在 com.ckjava.xutils.promise 包下
1 | <dependency> |