Java函数式接口日常使用
最近在开发过程中将Java 8 中函数接口使用到了业务开发中,方法灵活性和可复用性得到了很大的提升,方便业务的开发,下面来看看具体使用场景
有这样的一个业务 一直在操作实体对象中的各种属性 可能是 string obj int … 等各种类型那么每次对应的业务实现方法是这样的:
// obj 类型
public R<?> uploadTranslationInfo(InfoVO infoVO) {
InfoVO.UploadTranslationInfo uploadTranslationInfo = infoVO.getUploadTranslationInfo();
CommerceService updateInfo = newCommerceService();
updateInfo.setId(id);
// 保存 obj
updateFun.setUploadTranslationInfo(uploadTranslationInfo);
// 更新
this.update(updateInfo);
}
// str
public R<?> strInfo(InfoVO infoVO) {
String str = infoVO.getStr();
CommerceService updateInfo = newCommerceService();
updateInfo.setId(id);
// 保存 obj
updateFun.setStr(str);
// 更新
this.update(updateInfo);
}
// Int
public R<?> intInfo(InfoVO infoVO) {
Integer str = infoVO.getInt();
CommerceService updateInfo = newCommerceService();
updateInfo.setId(id);
// 保存 obj
updateFun.setInt(str);
// 更新
this.update(updateInfo);
}
通过上面简单的演示可以看到 每一个方法 大致流程都是一样的 其实完全可以抽取一个方法去实现一个“占位”作用 但是正常的抽取方法 对应的方法入参是固定的,int obj str 在传参一开始就固定了实现不了通用 这个时候就可以使用 public interface Consumer 这个函数接口
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
accept就是表示 执行你传入的代码块,就是类似 my Batis 中的 #{} 占位作用 可以实现统一方法抽取
那么对应的抽取方法实现:
public R<?> flowProcessObjectTypeParams(InfoVO infoVO,
Consumer<IncrementInfoVO> updateFun
) {
Integer str = infoVO.getInt();
CommerceService updateInfo = newCommerceService();
updateInfo.setId(id);
// 保存 各种类型
updateFun.accept(infoVO);
// 更新
this.update(updateInfo);
}
// 那么之前的方法就可以是这样,动态的传入不同类型的参数
// obj 类型
public R<?> uploadTranslationInfo(InfoVO infoVO) {
flowProcessObjectTypeParams(infoVO,item->{item.setTranslationInfo(infoVO.getTranslationInfo())})
}
// str
public R<?> strInfo(InfoVO infoVO) {
flowProcessObjectTypeParams(infoVO,item->{item.setStrInfo(infoVO.getStrInfo)})
}
// Int
public R<?> intInfo(InfoVO infoVO) {
flowProcessObjectTypeParams(infoVO,item->{item.setIntInfo(infoVO.getIntInfo())})
}
如果针对str 类型做进一步校验可以使用这个 public interface Function<T, R> 函数,场景 字符串 有校验的要求这个可以封装通用方法不用重复校验 在业务方法外部判断 字符串
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
传入一个T 返回一个R
那么可以写一个针对简单类型的通用方法:
@Transactional(rollbackFor = Exception.class)
public R<?> flowProcessSimpleTypeParams(IncrementInfoVO incrementInfoVO,
Function<IncrementInfoVO, String> fieldFun,
Consumer<IncrementInfoVO> updateFun
) {
// 获取对应的动态字段 str1 str2 str3
String field = fieldFun.apply(incrementInfoVO);
if (StringUtils.isEmpty(field) ) {
return R.fail("缺少参数");
}
Integer str = infoVO.getInt();
CommerceService updateInfo = newCommerceService();
updateInfo.setId(id);
// 保存 各种类型
updateFun.accept(infoVO);
// 更新
this.update(updateInfo);
}
}
以上就可以避免类型相同 但字段属性名称不同的问题:
// str1
public R<?> strInfo(InfoVO infoVO) {
flowProcessSimpleTypeParams(infoVO,item->{item.setStr1Info(infoVO.getStr1Info)})
}
// str2
public R<?> strInfo(InfoVO infoVO) {
flowProcessSimpleTypeParams(infoVO,item->{item.setStr2Info(infoVO.getStr2Info)})
}
通过 以上的2个 Function ,Consumer 函数式接口 可以感受到 使用函数式接口 作为方法参数 让方法具有比起以往更强大的灵活和通用型,在一些特定的场景真的可以方便很多,避免写重复业务流程代码,利于统一维护,在这个时间节点与大环境下确实不知道 代码写的更简洁是帮自己还是害自己 哎 ,好久分享了还是要捡起来 输入输出 ------@weng