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提供的一個(gè)新的類(lèi),凡是繼承了Serializable的函數(shù)式接口的實(shí)例都可以獲取一個(gè)屬于它的SerializedLambda實(shí)例,并且通過(guò)它獲取到方法的名稱(chēng),根據(jù)我們標(biāo)準(zhǔn)的java bean的定義規(guī)則就可以通過(guò)方法名稱(chēng)來(lái)獲取屬性名稱(chēng)。
實(shí)現(xiàn)
從lambda字節(jié)碼中獲取writeReplace
方法,反射調(diào)用返回lambda的SerializedLambda實(shí)例,再?gòu)腟erializedLambda實(shí)例中獲取方法名,然后將方法名轉(zhuǎn)換成屬性名
工具類(lèi)
/**
* @author niuyy
* @since 2020/3/20
*/
public class LambdaUtils {
/**
* 方法緩存
*/
private static Map<Class, SerializedLambda> CLASS_LAMBDA_CACHE = new ConcurrentHashMap<>();
/**
* 從lambda表達(dá)式獲取SerializedLambda實(shí)例
*
* @param fn lambda表達(dá)式
* @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;
}
/***
* 轉(zhuǎn)換方法引用為屬性名
*
* @param fn 方法引用
* @return 屬性名
*/
public static <T, R> String convertToFieldName(SFunction<T, R> fn) {
SerializedLambda lambda = getSerializedLambda(fn);
String methodName = lambda.getImplMethodName();
return methodToProperty(methodName);
}
/**
* 方法名轉(zhuǎn)換成屬性名
*
* @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;
}
}
總結(jié)
從SerializedLambda中還可以獲取其他信息:
image-20200323191947102.png
其中,implMethodKind 參考 MethodHandleInfo 類(lèi)
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
對(duì)于這樣的 lambda
String name1 = LambdaUtils.convertToFieldName((User u,String name2) -> {
String name3 = u.getName();
u.setName(name3 + 111);
});
SerializedLambda 信息如下
image-20200323192352796.png