經過Lambda的get方法引用拿到私有屬性名

前言:

最近在使用mybatis-plus框架,咱們都知道有這麼一種寫法,能夠經過lambda的方法引用得到屬性值,避免魔法值的大量出現java

public List<Board> getListByName() {
  LambdaQueryWrapper<Board> wrapper = new LambdaQueryWrapper<>();
  // lambda方法引用
  queryWrapper.eq(User::getName, "小明");
  return xxxserver.list(wrapper);
}
複製代碼

對於mybatis-plus的這類實現已經有博主寫了,不瞭解的能夠參考blog.csdn.net/u012503481/…這篇文章緩存

那麼咱們確定在不少開發場景須要用到Java Bean的屬性名,直接寫死屬性名字符串的形式容易產生bug(屬性名一旦變化,IDE不會告訴你你的字符串須要同步修改)。JDK8的Lambda能夠經過方法引用簡化代碼,一樣也能夠經過getter/setter的方法引用拿到屬性名,避免潛在的bug。mybatis

指望實現效果:

// 傳統方式:寫死屬性名
// 方法引用:替代字符串,當屬性名變化時IDE會同步提示,避免未同步產生bug
String userName = BeanUtils.convertToFieldName(User::getUserName);複製代碼

具體實現代碼封裝:

首先咱們定義1個函數式接口用來接收lambda方法引用表達式:注意函數式接口必定要繼承Serializable接口才能獲取方法信息。app

package com.changda.singleton;

import java.io.Serializable;

/** * @classname: SFunction * @create: 2019-09-25 12:57 **/
@FunctionalInterface
public interface SFunction<T> extends Serializable {
    Object get(T source);
}
複製代碼

其次咱們實現一個getter引用轉換屬性名的工具類【註釋基本都寫好啦,稍有不懂的話,自行百度一下】框架

package com.changda.singleton;


import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/** * @classname: BeanUtils * @create: 2019-09-25 18:13 **/
class BeanUtils {

    private static Map<Class, SerializedLambda> CLASS_LAMDBA_CACHE = new ConcurrentHashMap<>();

    /*** * 轉換方法引用爲屬性名 * @param fn * @return */
    static <T> String convertToFieldName(SFunction<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){
            System.out.println("無效的getter方法: "+ methodName);
        }
        // 截取get/is以後的字符串並轉換首字母爲小寫
       return toLowerCaseFirstOne(methodName.replace(prefix, ""));
    }

    /** * 首字母轉小寫 * @param s * @return */
     static String toLowerCaseFirstOne(String s){
        if(Character.isLowerCase(s.charAt(0)))
            return s;
        else
            return Character.toLowerCase(s.charAt(0)) + s.substring(1);
    }

    /** * 關鍵在於這個方法 */
     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) {
                e.printStackTrace();
            }
        }
        return lambda;
    }

}
複製代碼

測試:

先簡單建立一個實體類函數

package com.changda.singleton;

/** * @create: 2019-09-25 13:17 **/
public class Test {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
複製代碼

而後調用試試工具

package com.changda.singleton;

/** * @create: 2019-09-25 13:16 **/
public class Demo {
    public static void main(String[] args) {
        System.out.println(BeanUtils.convertToFieldName(Test::getName));
    }
}

複製代碼

結果以下:測試

這樣就大功告成了,能夠使用方法引用了,不再用擔憂打錯字符咯。this

相關文章
相關標籤/搜索