最近在思考lambda相关的问题,简单记录下做的相关反射替代和函数映射的尝试。
原理分析
lambda是jdk8才提供的,原理其实就是动态生成内部类来执行函数映射的方法。也就是说一段lambda表达式会对应特定的类方法,之后调用。底层是通过LambdaMetaFactory实现的函数映射,利用了jdk7给出的MethodHandler之类的函数式编程相关类来实现对函数的映射,MethodType用于函数签名。
反射的话基本接触过java的都听说过,底层实现是利用了native的invoke方法,因此说大量使用反射会影响性能,毕竟调用native方法开销会更大一点。
那么,只要利用LambdaMetaFactory或者函数式编程语法糖来获取对应的方法,并在类初始化的情况下进行构建,那么之后利用该对象调用对应方法,就会和直接调用原始方法一样快,因为本质上是在调用生成的内部类的方法。
简单尝试
首先是直接使用反射的方法,对一个User类对象获取其中的Method,invoke直接调用。
反射大家都会,直接给出实现。
用户类,包括函数编程接口User和实现类
@FunctionalInterface
public interface User {
String getId();
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SimpleUser implements User{
String id;
String name;
}
反射类实现
// 简单反射调用user中方法
public class UserReflectAdaptor {
public static String reflectUserId(SimpleUser user) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<? extends SimpleUser> c = user.getClass();
Method method = c.getMethod("getId");
return (String) method.invoke(user);
}
public static void main(String[] args){
SimpleUser user = new SimpleUser("123", "mage");
try {
System.out.println(reflectUserId(user));
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
简单获取Method对象,并使用invoke方法实现代理调用。
lambda表达式实现
lambda表达式进行函数映射基本有数种方法,比较简单的是直接利用::
获取函数对象
static User user;
@Benchmark
public static String lambdaUserId() {
Supplier<String> idGetter = user::getId;
return idGetter.get