美文网首页
2020-03-19-Java8使用Lamda代替字符串

2020-03-19-Java8使用Lamda代替字符串

作者: Noah牛YY | 来源:发表于2020-03-25 19:08 被阅读0次

    layout: post
    title: Java8使用Lamda代替字符串
    categories: [Java]
    description: Java8新特性
    keywords: Java


    效果

    public class User {
        private String name;
    
        public String getName() {
            return name;
        }
    }
    
    public static void main(String[] args) {
        String name = LambdaUtils.convertToFieldName(User::getName);
        System.out.println(name); //name
    }
    

    原理

    SerializedLambda

    是jdk1.8提供的一个新的类,凡是继承了Serializable的函数式接口的实例都可以获取一个属于它的SerializedLambda实例,并且通过它获取到方法的名称,根据我们标准的java bean的定义规则就可以通过方法名称来获取属性名称。

    实现

    从lambda字节码中获取writeReplace方法,反射调用返回lambda的SerializedLambda实例,再从SerializedLambda实例中获取方法名,然后将方法名转换成属性名

    工具类

    /**
     * @author niuyy
     * @since 2020/3/20
     */
    public class LambdaUtils {
    
        /**
         * 方法缓存
         */
        private static Map<Class, SerializedLambda> CLASS_LAMBDA_CACHE = new ConcurrentHashMap<>();
    
        /**
         * 从lambda表达式获取SerializedLambda实例
         *
         * @param fn lambda表达式
         * @return 获取SerializedLambda
         */
        public static SerializedLambda getSerializedLambda(Serializable fn) {
            SerializedLambda lambda = CLASS_LAMBDA_CACHE.get(fn.getClass());
            if (lambda == null) {
                try {
                    Method method = fn.getClass().getDeclaredMethod("writeReplace");
                    method.setAccessible(Boolean.TRUE);
                    lambda = (SerializedLambda) method.invoke(fn);
                    CLASS_LAMBDA_CACHE.put(fn.getClass(), lambda);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            return lambda;
        }
    
        /***
         * 转换方法引用为属性名
         *
         * @param fn 方法引用
         * @return 属性名
         */
        public static <T, R> String convertToFieldName(SFunction<T, R> fn) {
            SerializedLambda lambda = getSerializedLambda(fn);
            String methodName = lambda.getImplMethodName();
            return methodToProperty(methodName);
        }
    
        /**
         * 方法名转换成属性名
         *
         * @param name 方法名
         * @return 属性名
         */
        public static String methodToProperty(String name) {
            if (name.startsWith("is")) {
                name = name.substring(2);
            } else if (name.startsWith("get") || name.startsWith("set")) {
                name = name.substring(3);
            } else {
                throw new RuntimeException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
            }
    
            if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) {
                name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
            }
    
            return name;
        }
    
    }
    

    总结

    从SerializedLambda中还可以获取其他信息:

    image-20200323191947102.png

    其中,implMethodKind 参考 MethodHandleInfo 类

    static final byte
                REF_NONE                    = 0,  // null value
                REF_getField                = 1,
                REF_getStatic               = 2,
                REF_putField                = 3,
                REF_putStatic               = 4,
                REF_invokeVirtual           = 5,
                REF_invokeStatic            = 6,
                REF_invokeSpecial           = 7,
                REF_newInvokeSpecial        = 8,
                REF_invokeInterface         = 9,
                REF_LIMIT                  = 10;
    

    MORE

    对于这样的 lambda

    String name1 = LambdaUtils.convertToFieldName((User u,String name2) -> {
                String name3 = u.getName();
                u.setName(name3 + 111);
            });
    

    SerializedLambda 信息如下

    image-20200323192352796.png

    相关文章

      网友评论

          本文标题:2020-03-19-Java8使用Lamda代替字符串

          本文链接:https://www.haomeiwen.com/subject/lzixuhtx.html