使用SFunction获取属性名,减少嵌入硬编码
目录
问题引入
一、SFunction获取属性名称
二、选用方法
驼峰命名转换为下划线命名
下划线命名转换为驼峰命名
三、使用
问题引入
在编写代码时,有一些变量值需要实体类属性或对应数据库字段的硬编码
例如,SysUser类中有属性 realName
常常在map中调用,
map.put("realName","真实名称") 或者 map.get("real_name")
这种属性变量名一般直接编写成字符串嵌入在代码中
如果未来我们需要修改 realName的名称,那么不仅需要修改实体类中字段名,还常常需要依次找到并修改用到的硬编码;
也可以选择全文检索替换,但是命名相同的变量也会被迫修改
那么如果常用SFuction,就想利用属性的get方法反射获取到属性名的替代硬编码
这样,利用idea工具直接Shift + F6修改属性名称,对应的get和set方法也会同步修改,避免了需要手动查找替换
一、SFunction获取属性名称
/*** 使用SFunction获取属性名** @param function SFunction get方法* @return 属性名*/
public static <T, R> String getFieldNameWithSFunction(SFunction<T, R> function) {try {// 获取Lambda表达式的序列化信息Method method = function.getClass().getDeclaredMethod("writeReplace");method.setAccessible(true);SerializedLambda serializedLambda = (SerializedLambda) method.invoke(function);// 获取Lambda引用的方法名String methodName = serializedLambda.getImplMethodName();// 根据方法名推断属性名(假设是getter方法)if (methodName.startsWith("get") && methodName.length() > 3) {return methodName.substring(3, 4).toLowerCase() + methodName.substring(4);} else if (methodName.startsWith("is") && methodName.length() > 2) {return methodName.substring(2, 3).toLowerCase() + methodName.substring(3);}} catch (Exception e) {throw new RuntimeException("Failed to extract property name from lambda", e);}throw new IllegalArgumentException("Invalid lambda expression for property extraction");
}
二、选用方法
驼峰命名转换为下划线命名
/*** 将驼峰命名法转换为下划线命名法** @param camelCase 驼峰命名法* @return 下划线命名法*/
public static String getUnderLineFromCamelCase(String camelCase) {if (camelCase == null) {return null;}StringBuilder sb = new StringBuilder();for (int i = 0; i < camelCase.length(); i++) {char c = camelCase.charAt(i);if (Character.isUpperCase(c)) {sb.append("_").append(Character.toLowerCase(c));} else {sb.append(c);}}return sb.toString();
}
下划线命名转换为驼峰命名
/*** 下划线命名转换为驼峰命名** @param underLine 下划线命名法* @return 驼峰命名法*/public static String getCamelCaseFromUnderLine(String underLine) {if (underLine == null) {return null;}StringBuilder sb = new StringBuilder();for (int i = 0; i < underLine.length(); i++) {char c = underLine.charAt(i);if (c == '_') {i++;sb.append(Character.toUpperCase(underLine.charAt(i)));} else {sb.append(c);}}return sb.toString();}
三、使用
//map需要使用实体属性字段名称,直接通过get方法获取
LinkedHashMap<String, String> headMap = new LinkedHashMap<>();
headMap.put(ConvertUtil.getFieldNameWithSFunction(ApplicationTaskVO::getApplicationType), "申请类型");//MyBatis 的 QueryWrapper要使用数据库字段名称,先获取属性字段名再转换为下划线格式
queryWrapper.eq(ConvertUtil.getUnderLineFromCamelCase(ConvertUtil.getFieldNameWithSFunction(ApplicationRepair::getApplicant)), sysUser.getUsername());//申请人=用户名
当需要修改时,选中实体中字段,Shift + F6,输入新的属性名,全部引用位置也同步修改