Lambda实践

Lambda的函数式编程让我想起了C#的委托写法,感觉挺有趣的,打算在自己的项目中写个测试;

1. 使用Lambda前

使用Lambda前的API层,每写一个API都要写一遍下面的代码,重复代码繁多

@ApiOperation(value = "没有使用Lambda的方法", notes = ("没有使用Lambda的方法"))
@RequestMapping(value = "/notlambda", method = RequestMethod.POST)
public RestResponse<TestResVo> notlambda(@Valid @RequestBody TestReqVo vo, BindingResult result) {
    if (result.hasErrors()) {
        return new RestResponse<>(RestRespCode.PARAM_ERROR, getErrors(result, vo), null);
    }
    RestResponse<TestResVo> rest;
    try {
        rest = testBusinessService.test3(vo);
        if (!rest.isSuccess()) {
            return new RestResponse(rest.getCode(), rest.getMsg(), rest.getData());
        }
    } catch (Exception ex) {
        LOG.error("testApi => hello4 :" +JsonMapper.toJson(vo), ex.getMessage(), ex);
        return new RestResponse<TestResVo>(RestRespCode.SYS_ERROR, message(MessageKeys.SYS_ERROR), null);
    }
    return new RestResponse<TestResVo>(RestRespCode.OK, message(MessageKeys.SYSTEM_SUCCESS), rest.getData());
}

2. 使用Lambda后

  1. 编写自定义函数式接口,这是我根据自己的需求所定义的函数式接口
@FunctionalInterface
public interface ApiSupplier {
    RestResponse get();
}
  1. 编写一个公共API父类ApiSupplierExec,把重复代码提取出来
public class ApiSupplierExec extends BaseApi {

    private static final Logger LOG = LoggerFactory.getLogger(ApiSupplierExec.class);

    /**
     * @param supplier 要执行的方法函数
     * @param result 实体参数验证
     * @param r 请求参数
     */
    public RestResponse exec(ApiSupplier supplier, BindingResult result, Object... r){
        if (result.hasErrors()) {
            return new RestResponse<>(RestRespCode.PARAM_ERROR, getErrors(result, r), null);
        }
        return exec(supplier, r);
    }

    /**
     * @param supplier 要执行的方法函数
     * @param r 请求参数
     */
    public RestResponse exec(ApiSupplier supplier, Object... r){
        RestResponse rest;
        try {
            rest = supplier.get();
            if (!rest.isSuccess()) {
                return new RestResponse(rest.getCode(), rest.getMsg(), rest.getData());
            }
        } catch (Exception ex) {
            String param = r.length>0 ? Arrays.stream(r).map(o -> o.toString()).collect(Collectors.joining("; ")) : JsonMapper.toJson(r);
            String className = getClassName();
            String methodName = getMethodName();
            LOG.error(className + " => " + methodName + " :" +param, ex.getMessage(), ex);
            return new RestResponse(RestRespCode.SYS_ERROR, message(MessageKeys.SYS_ERROR), null);
        }
        return new RestResponse(RestRespCode.OK, message(MessageKeys.SYSTEM_SUCCESS), rest.getData());
    }

    /**
     * 获取哪个api调用了该方法
     * @return
     */
    private static String getClassName(){
        // Thread.currentThread().getStackTrace()[0]  得到getStackTrace方法的名字
        // Thread.currentThread().getStackTrace()[1]  得到当前方法的名字
        // Thread.currentThread().getStackTrace()[2]  得到调用当前方法的方法的名字
        return Thread.currentThread().getStackTrace()[3].getClassName();
    }

    /**
     * 获取哪个方法调用了该方法
     * @return
     */
    private static String getMethodName(){
        return Thread.currentThread().getStackTrace()[3].getMethodName();
    }
}
  1. 优化后的API层接口代码
@ApiOperation(value = "使用Lambda的方法", notes = ("使用Lambda的方法"))
@RequestMapping(value = "/lombda", method = RequestMethod.POST)
public RestResponse<TestResVo> lombda(@RequestBody TestReqVo vo) {
    // 优化后的每个API方法只需关注主业务方法的调用
    ApiSupplier action = () -> testBusinessService.test2(vo);
    return exec(action, vo);
}
  1. 调用过程
  • 使用Lambda后,可以将主业务代码赋值给ApiSupplier(函数式接口)
ApiSupplier action = () -> testBusinessService.test2(vo);
  • 在将内含业务代码的函数式接口传给父类的exec方法
return exec(action, vo);
  • 在exec方法中,调用函数式接口的get方法,执行我们的业务代码
rest = supplier.get();
  1. 其他示例代码
  • 函数式接口
@FunctionalInterface
public interface ServiceFunction<M> {
    Response get(M m);
}
  • 抽取的公用代码
/**
  * @description 抽离出来的公用方法
  * @param function 要执行的方法函数
  * @param v 要转换成的VO
  * @param r 请求参数
  * @param m 调用业务层的参数的实体类型
  */
public static <V, M, R> RestResponse<V> exec(ServiceFunction<M> function, Class<V> v, Class<M> m, R r){
    M model = BeanMapperUtil.map(r, m);
    Response restModel = function.get(model);
    if (restModel != null) {
        V result = BeanMapperUtil.map(restModel.getData(), v);
        return new RestResponse<V>(restModel.getCode(), restModel.getMsg(), result);
    }
    return new RestResponse<V>(RestRespCode.SYS_ERROR, MessageUtil.getMessage(MessageKeys.SYS_ERROR), null);
}
  • 业务调用
public RestResponse<TestResVo> lambda(TestReqVo vo) {
    ServiceFunction<TestReqModel> action = (model) -> testService.test2(model);
    return ServiceSupplierExec.exec(action, TestResVo.class, TestReqModel.class, vo);
}

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

那一年,我也变成了光!!