Lombok是一个Java库,它会自动插入编辑器和构建工具中,Lombok提供了一组有用的注解,用来消除Java类中的大量样板代码。
1. Lombok 环境配置
lombok.jar
包下载并导入:https://projectlombok.org/download
- IDEA Lombok 插件安装:Settings >> Plugins 搜索安装
- IDEA 打开注解开发:Settings >> Build >> Compiler >>
☑
Enable annotation processing
2. Lombok 基本用法
@Getter / @Setter 源码
1 2 3 4 5 6 7
| @Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface Getter { AccessLevel value() default AccessLevel.PUBLIC; ... }
|
@ToString 源码
1 2 3 4 5 6 7 8 9
| @Target({ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface ToString { boolean includeFieldNames() default true; String[] exclude() default {}; String[] of() default {}; ... }
|
@NoArgsConstructor / @AllArgsConstructor 源码
1 2 3 4 5 6 7 8
| @Target({ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface NoArgsConstructor { ... AccessLevel access() default AccessLevel.PUBLIC; ... }
|
@Data 源码
1 2 3 4 5
| @Target({ElementType.TYPE}) @Retention(RetentionPolicy.SOURCE) public @interface Data { String staticConstructor() default ""; }
|
2.1 注解组合×3
@Data
@NoArgsConstructor
@AllArgsConstructor
demo - 生成 get / set / equals / canEqual / hashCode / toString / 无参构造 / 有参构造
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
@Data @NoArgsConstructor @AllArgsConstructor public class User { private Integer id; private String username; private String password; private String email; }
|
2.2 链式编程
@Builder
使用 @SuperBuilder(toBuilder=true) 代替,在lombok较新的版本比如大于 1.18.8 上可以解决 @Builder 不支持继承的父类属性的问题。
1 2 3 4 5 6 7 8 9 10
| @Data @SuperBuilder(toBuilder=true) @AllArgsConstructor @NoArgsConstructor public class UserInfo { private String id; private String name; @Builder.Default private String password = "123456"; }
|
- @Builder(toBuilder=true) 同时支持属性初始化和修改:
1 2 3 4
| UserInfo jerry = UserInfo.builder().id("123").name("jerry").password("666").build();
UserInfo tom = jerry.toBuilder().name("tom").password("888").build();
|
- @Data和@Builder导致无参构造丢失 以及 @Builder注解导致默认值无效,因此使用常用组合即可
1
| 常用组合:@Data, @SuperBuilder(toBuilder=true), @AllArgsConstructor, @NoArgsConstructor
|
@Accessors
@Accessors 是用来配置lombok如何产生和显示getters和setters的注解,可以用在类或方法上面。
@Accessors有三个属性,分别是fluent
,chain
,prefix
- fluent 属性
fluent设置为true,则getter和setter方法的方法名和属性名一模一样,且setter方法返回当前对象 ,该属性默认为false。
1 2 3 4 5 6 7 8 9 10 11 12
| @Data @Accessors(fluent = true) public class User { private Long id; private String name; public Long id() {} public User id(Long id) {} public String name() {} public User name(String name) {} }
|
- chain属性
chain设置为true,则setter方法返回当前对象。该属性默认为false,(如果当fluent为true时,chain默认则为true).
1 2 3 4 5 6 7 8 9 10
| @Data @Accessors(chain = true) public class User { private Long id; private String name; public User setId(Long id) {} public User setName(String name) {} }
|
- prefix属性
prefix可以指定前缀,生成get/set方法时会去掉指定的前缀
1 2 3 4 5 6 7 8 9 10 11 12
| @Data @Accessors(prefix = "p") public class User { private Long pId; private String pName; public Long getId() {} public void setId(Long id) {} public String getName() {} public void setName(String name) {} }
|
对比和坑
@Builder就是基于建造者模式支持链式操作,但很多时候都是构造失血模式的Bean或者没有共享变量,这时候为了链式操作就新建一个builder是不是有点大材小用
示例:实体类加上@Builder注解(目前更新为@SuperBuilder )
@Accessors就可以解决上述的问题,支持链式操作,同时减少多余对象的创建,builder类元信息又可以减少
示例:实体类加上@Accessors(chain = true)注解
1 2 3 4
| UserInfo jerry = UserInfo.builder().id("123").name("jerry").password("666").build();
UserInfo jerry = new UserInfo().setId("123").setName("jerry").setPassword("666");
|
坑:有的开源反射工具包对对象进行浅拷贝时,获取set方法元信息时会判断方法返回值是否是void,这时候@Accessors就会出现异常。
@Singular
1 2 3 4 5 6 7 8 9 10 11 12
| @Builder @Data @AllArgsConstructor @NoArgsConstructor class UserBean { private Integer id; private String userName; @Default private String example = "123456"; @Singular private List<String> favorites; }
|
1 2 3 4 5
| UserBean u = UserBean.builder().id(1001).userName("polly") .favorite("music") .favorite("movie") .build();
|
@SuperBuilder
因为 @Builder 并不支持父类成员属性的构造,使用 @SuperBuilder 可以解决次问题,对于 toBuilder = true 在父类也需要同时添加。
1 2 3 4 5 6 7 8 9
| @SuperBuilder(toBuilder = true) public class Person { private Integer age; private String name; }
@SuperBuilder(toBuilder = true) public class Ming extends Person { }
|
1 2 3 4 5
| Ming mingD = Ming.builder() .age(11) .name("小明") .build(); Ming mingF = mingD.toBuilder().name("猪").build();
|
2.3 @SneakyThrows
在java
的异常体系中Exception
异常有两个分支,一个是运行时异常RuntimeException
,一个是编译时异常,在Exception
下的所有非RuntimeException
异常,比如IOException
、SQLException
等;所有的运行时异常不捕获,编译时异常是一定要捕获,否则编译会报错。@SneakyThrows
就是利用了这一机制,将当前方法抛出的异常,包装成RuntimeException
,骗过编译器,使得调用点可以不用显示处理异常信息。
1 2 3 4 5 6 7 8 9
|
@SneakyThrows private void sneakyThrowsTest() { SneakyThrowsDemo.class.newInstance(); }
|
简言之,不想 try-catch的时候,可以使用此注解修饰方法。异常依然会被捕获,只是不用写。