Java编程学习:SAO操作-使用lambda代替字符串!
Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互联网,同时拥有全球最大的开发者专业社群。
给你学习路线:html-css-js-jq-javase-数据库-jsp-servlet-Struts2-hibernate-mybatis-spring4-springmvc-ssh-ssm
Java8新增了lambda表达式,最常见的用法是配合 Stream 做集合操作。下面是一种类似彩蛋的东西可以妙用到某些场合。
一般用法,比如下面这样
Optional.of(1L).ifPresent(number -> { System.out.println(number);});
或者简化成这样
Optional.of(1L).ifPresent(System.out::println);
有什么办法能获取到 System.out::println 里面的方法名字符串 String methodName = "println" ?
啥效果?
小编推荐一个学Java的学习裙【 七六零,二五零,五四一 】,无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享!
执行代码
FnConverter fnConverter = new FnConverter<>();String fieldName = fnConverter.convertFnToString(Foo::getBar);System.out.println("方法名:"+fieldName);
输出
方法名:bar
怎么做?
第一步:定义一个 FunctionalInterface (敲黑板,画重点 extends Serializable )
/** * @author Frank */@FunctionalInterfacepublic interface Fn extends Serializable { Object apply(T source);}
第二布:准备个类(酱油)
import lombok.Data;/** * @author liuyuyu */@Datapublic class Foo { private Integer bar;}
第三步:获取 Fn 的信息的工具类
import java.beans.Introspector;import java.lang.invoke.SerializedLambda;import java.lang.reflect.Method;/** * @author Frank */public class Reflections { private Reflections() { } public static String fnToFieldName(Fn fn) { try { Method method = fn.getClass().getDeclaredMethod("writeReplace"); method.setAccessible(Boolean.TRUE); SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn); String getter = serializedLambda.getImplMethodName(); String fieldName = Introspector.decapitalize(getter.replace("get", "")); return fieldName; } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } }}
画重点 SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
第四步:写个梨子跑起来
/** * @author liuyuyu */public class FnConverter { public String convertFnToString(Fn fn){ return Reflections.fnToFieldName(fn); } public static void main(String[] args) { FnConverter fnConverter = new FnConverter<>(); String fieldName = fnConverter.convertFnToString(Foo::getBar); System.out.println("方法名:"+fieldName); }}
Run
方法名:bar
啥原理?
Serializable 是Java对象序列化的接口,凡是实现这个接口(interface是继承,也算)Java都要提供序列化和反序列化的方法( ObjectInputStream/ObjectOutputStream 可能会让你想起点什么)。
但是lambda比较特殊,它是一个方法,可以认为是一个动作(或者说是功夫?比如九阴真经),没办法直接保存,Java提供了 SerializedLambda 这个类保存lambda的信息。
public final class SerializedLambda implements Serializable { private static final long serialVersionUID = 8025925345765570181L; private final Class capturingClass; private final String functionalInterfaceClass; private final String functionalInterfaceMethodName; private final String functionalInterfaceMethodSignature; private final String implClass; private final String implMethodName; private final String implMethodSignature; private final int implMethodKind; private final String instantiatedMethodType; private final Object[] capturedArgs; //省略之后代码}
小编推荐一个学Java的学习裙【 七六零,二五零,五四一 】,无论你是大牛还是小白,是想转行还是想入行都可以来了解一起进步一起学习!裙内有开发工具,很多干货和技术资料分享!
知道了这个隐藏(彩)特性(蛋),我们回头看看刚才黑板上画的重点
@FunctionalInterface //lambdapublic interface Fn extends Serializable //序列化接口
两个条件满足
因为这个东西是个隐藏(彩)特性(蛋),我们不能直接获取到 SerializedLambda 。直接上反射!
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
这样,我们就可以获取到lambda的方法名