背景
在编码时经常会用到同名的属性名字符串,比如
- 用相同的属性名做为 map 中的键;
- 在 mybatis 中,根据属性名的下划线字符串来拼接 sql 查询条件。
需要修改属性名时,如果是用字符串硬编码的,引用的地方越多,修改越困难
但是如果用的是 java8 中的属性引用,操作起来就很方便了,修改一处即可修改全部相关引用。
属性工具类测试
参考下面测试类,怎样使用;
如果想要修改 articleName
为 articleTitle
,
在 IDEA 中,修改类的属性名很方便,选中属性名 articleName,按下快捷键 <Shift + F6>,键入新的属性名称 articleTitle,确认即可替换所有关联的属性名称
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import lombok.Getter; import lombok.Setter;
public class FieldUtilTest {
@Setter @Getter static class Article { String articleName; String articleContent; }
public static void main(String[] args) {
System.out.println(FieldUtil.noPrefix(Article::getArticleName)); System.out.println(FieldUtil.underline(Article::getArticleName)); System.out.println(FieldUtil.underlineUpper(Article::getArticleContent)); System.out.println(FieldUtil.toSymbolCase(Article::getArticleName, '$'));
System.out.println(FieldUtil.noPrefix(Article::setArticleName)); System.out.println(FieldUtil.underline(Article::setArticleName)); System.out.println(FieldUtil.underlineUpper(Article::setArticleContent)); System.out.println(FieldUtil.toSymbolCase(Article::setArticleName, '$')); } }
|
属性工具类代码
关键逻辑是利用了 java8 中的 SerializedLambda 的 getImplMethodName 方法来获取属性名。
源码中引用了 hutool 第三方工具类的 StrUtil
工具,方便操作字符串,当然也可自行开发。
参考资料:利用 Lambda 实现通过 getter/setter 方法引用拿到属性名 - SegmentFault 思否
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
| import cn.hutool.core.util.StrUtil;
import java.io.Serializable; import java.lang.invoke.SerializedLambda; import java.lang.reflect.Method;
public class FieldUtil {
public static <T> String underline(IGetter<T> fn) { return toSymbolCase(fn, '_'); }
public static <T> String underlineUpper(IGetter<T> fn) { return underline(fn).toUpperCase(); }
public static <T> String toSymbolCase(IGetter<T> fn, char symbol) { return StrUtil.toSymbolCase(noPrefix(fn), symbol); }
public static <T> String noPrefix(IGetter<T> fn) { return getGeneralField(fn); }
public static <T, R> String underline(ISetter<T, R> fn) { return toSymbolCase(fn, '_'); }
public static <T, R> String underlineUpper(ISetter<T, R> fn) { return underline(fn).toUpperCase(); }
public static <T, R> String toSymbolCase(ISetter<T, R> fn, char symbol) { return StrUtil.toSymbolCase(noPrefix(fn), symbol); }
public static <T, R> String noPrefix(ISetter<T, R> fn) { return getGeneralField(fn); }
private static String getGeneralField(Serializable fn) { SerializedLambda lambda = getSerializedLambda(fn); String getOrSetMethodName = lambda.getImplMethodName(); final String generalField = StrUtil.getGeneralField(getOrSetMethodName); return StrUtil.isEmpty(generalField) ? getOrSetMethodName : generalField; }
private static SerializedLambda getSerializedLambda(Serializable fn) { SerializedLambda lambda; try {
Method method = fn.getClass().getDeclaredMethod("writeReplace"); method.setAccessible(Boolean.TRUE); lambda = (SerializedLambda) method.invoke(fn); } catch (Exception e) { throw new IllegalArgumentException("获取SerializedLambda异常, class=" + fn.getClass().getSimpleName(), e); } return lambda; }
@FunctionalInterface public interface IGetter<T> extends Serializable { Object apply(T source); }
@FunctionalInterface public interface ISetter<T, U> extends Serializable { void accept(T t, U u); } }
|