有很多开发场景需要用到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 - 简单高效的轻代码开发框架