共计 2016 个字符,预计需要花费 6 分钟才能阅读完成。
有很多开发场景需要用到 Java Bean 的属性名,直接写死属性名字符串的形式容易产生 bug(属性名一旦变化,IDE 不会告诉你你的字符串需要同步修改)。JDK8 的 Lambda 可以通过方法引用简化代码,同样也可以通过 getter/setter 的方法引用拿到属性名,避免潜在的 bug。
1. 定义 FunctionalInterface 接收方法引用
/**
* getter 方法接口定义
*/
@FunctionalInterface
public interface IGetter<T> extends Serializable {Object apply(T source);
}
/**
* setter 方法接口定义
*/
@FunctionalInterface
public interface ISetter<T, U> extends Serializable {void accept(T t, U u);
}
2. 定义 getter/setter 引用转换属性名的工具类
public class BeanUtils {
...
/**
* 缓存类 -Lambda 的映射关系
*/
private static Map<Class, SerializedLambda> CLASS_LAMDBA_CACHE = new ConcurrentHashMap<>();
/***
* 转换方法引用为属性名
* @param fn
* @return
*/
public static <T> String convertToFieldName(IGetter<T> fn) {SerializedLambda lambda = getSerializedLambda(fn);
String methodName = lambda.getImplMethodName();
String prefix = null;
if(methodName.startsWith("get")){prefix = "get";}
else if(methodName.startsWith("is")){prefix = "is";}
if(prefix == null){log.warn("无效的 getter 方法:"+methodName);
}
// 截取 get/is 之后的字符串并转换首字母为小写(S 为 diboot 项目的字符串工具类,可自行实现)return S.uncapFirst(S.substringAfter(methodName, prefix));
}
/***
* 转换 setter 方法引用为属性名
* @param fn
* @return
*/
public static <T,R> String convertToFieldName(ISetter<T,R> fn) {SerializedLambda lambda = getSerializedLambda(fn);
String methodName = lambda.getImplMethodName();
if(!methodName.startsWith("set")){log.warn("无效的 setter 方法:"+methodName);
}
// 截取 set 之后的字符串并转换首字母为小写(S 为 diboot 项目的字符串工具类,可自行实现)return S.uncapFirst(S.substringAfter(methodName, "set"));
}
/***
* 获取类对应的 Lambda
* @param fn
* @return
*/
private static SerializedLambda getSerializedLambda(Serializable fn){
// 先检查缓存中是否已存在
SerializedLambda lambda = CLASS_LAMDBA_CACHE.get(fn.getClass());
if(lambda == null){
try{// 提取 SerializedLambda 并缓存
Method method = fn.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
lambda = (SerializedLambda) method.invoke(fn);
CLASS_LAMDBA_CACHE.put(fn.getClass(), lambda);
}
catch (Exception e){log.error("获取 SerializedLambda 异常, class="+fn.getClass().getSimpleName(), e);
}
}
return lambda;
}
}
3. 开心的引用
// 方法引用替代 hard code 字符串,属性名变化时 IDE 会同步提示
String ITEM_NAME = BeanUtils.convertToFieldName(User::getOrgName);
// 等同于 String ITEM_NAME = "orgName";
Diboot – 简单高效的轻代码开发框架
正文完