有很多开发场景需要用到Java Bean的属性名,直接写死属性名字符串的形式容易产生bug(属性名一旦变化,IDE不会告诉你你的字符串需要同步修改)。JDK8的Lambda可以通过方法引用简化代码,同样也可以通过getter/setter的方法引用拿到属性名,避免潜在的bug。
1. 定义FunctionalInterface 接收方法引用
/** * getter方法接口定义 */@FunctionalInterfacepublic interface IGetter<T> extends Serializable { Object apply(T source);}/** * setter方法接口定义 */@FunctionalInterfacepublic 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 - 简单高效的轻代码开发框架