@Getter、@Setter
可以使用 @Getter 或 @Setter 注释任何类或字段,Lombok 会自动生成默认的 getter/setter 方法。如果该字段被称为 foo,则 getter 的方法名为 getFoo;如果该字段的类型为 boolean,则为 isFoo。当在类上使用该注释时,该注释会注释该类中的所有非静态字段。
@Target({ElementType.FIELD, ElementType.TYPE})@Retention(RetentionPolicy.SOURCE)public @interface Getter {// 生成的getter方法的访问级别lombok.AccessLevel value() default lombok.AccessLevel.PUBLIC;// 废弃AnyAnnotation[] onMethod() default {};// 是否启用延迟初始化boolean lazy() default false;}
默认生成的 getter/setter 方法是公共的,除非你明确指定一个 AccessLevel。
public enum AccessLevel {PUBLIC, MODULE, PROTECTED, PACKAGE, PRIVATE,/** Represents not generating anything or the complete lack of a method. */NONE;}
可以使用特殊的 AccessLevel.NONE 访问级别来手动禁用任何字段的 getter/setter 自动生成。这使得我们可以覆盖类上的 @Getter,@Setter 或 @Data 注释的行为。
@Getter 注解还支持一个 lazy 属性,该属性默认为 false。当设置为 true 时,会启用延迟初始化,即当首次调用相应 getter 方法时才进行初始化,内部通过同步代码块进行首次初始化。
构造函数
1. @NoArgsConstructor
使用 @NoArgsConstructor 注解可以为指定类生成默认构造函数,@NoArgsConstructor 注解定义如下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.SOURCE)public @interface NoArgsConstructor {/*** 如果设置了该属性,生成的构造函数将会是私有的,并且生成一个staticName指定的静态构造方法(内部调用构造函数)*/String staticName() default "";/*** 设置生成的构造函数的访问级别,默认是public*/AccessLevel access() default lombok.AccessLevel.PUBLIC;/*** 若设置为true,则初始化所有final的字段为0/null/false* 如果为false,当有final字段存在时编译器会报错*/boolean force() default false;}
代码示例:
@NoArgsConstructor(staticName = "getInstance")public class NoArgsConstructorDemo {private long id;private String name;private int age;}
以上代码经过 Lombok 编译后,会生成如下代码:
public class NoArgsConstructorDemo {private long id;private String name;private int age;private NoArgsConstructorDemo() {}public static NoArgsConstructorDemo getInstance() {return new NoArgsConstructorDemo();}}
2. @AllArgsConstructor
使用 @AllArgsConstructor 注解可以为指定类生成包含所有成员的构造函数。
3. @RequiredArgsConstructor
使用 @RequiredArgsConstructor 注解可以为指定类初始化必需的成员变量,如 final 成员变量,针对必需初始化的成员变量生成对应的构造函数。
@EqualsAndHashCode
使用 @EqualsAndHashCode 注解可以为指定类生成 equals 和 hashCode 方法,默认使用的是所有非 static、非 transient 修饰的字段,且不考虑父类属性。@EqualsAndHashCode 注解的定义如下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.SOURCE)public @interface EqualsAndHashCode {/*** 如果为true,则子类生成的equals和hashCode方法会调用父类的相应方法*/boolean callSuper() default false;/*** 如果字段的getter方法可用,在生成的equals和hashCode方法中会调用它们,否则直接访问字段。* 如果设置为true,则始终会使用直接字段访问而不会调用字段的getter方法。*/boolean doNotUseGetters() default false;/*** 如果为true,则生成的equals和hashCode方法仅包含显式标记为@EqualsAndHashCode.Include的字段和方法。* 如果为false,则默认包含所有非static、非transient字段。*/boolean onlyExplicitlyIncluded() default false;/*** 如果想要在生成的equals和hashCode方法中排除某字段,则通过该注解修饰对应字段*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.SOURCE)public @interface Exclude {}/*** 如果想要在生成的equals和hashCode方法中使用某字段,则通过该注解修饰对应字段* 需要将onlyExplicitlyIncluded设为true,来精确控制使用的字段*/@Target({ElementType.FIELD, ElementType.METHOD})@Retention(RetentionPolicy.SOURCE)public @interface Include {String replaces() default "";}}
@EqualsAndHashCode.Exclude 代码示例:
public class EqualsAndHashCodeExample {public static void main(String[] args) {Person person1 = new Person("a", "1");Person person2 = new Person("b", "1");System.out.println(person1.equals(person2));}@EqualsAndHashCode@AllArgsConstructorprivate static class Person {@EqualsAndHashCode.Excludeprivate final String name;private final String identity;}}// 输出为:true
@EqualsAndHashCode.Include 代码示例:
public class EqualsAndHashCodeExample {public static void main(String[] args) {Person person1 = new Person("a", "1");Person person2 = new Person("b", "1");System.out.println(person1.equals(person2));}@EqualsAndHashCode(onlyExplicitlyIncluded = true)@AllArgsConstructorprivate static class Person {private final String name;@EqualsAndHashCode.Includeprivate final String identity;}}// 输出为:true
callSuper 使用示例:
public class EqualsAndHashCodeExample {public static void main(String[] args) {Employee employee1 = new Employee("a", "1", "A");Employee employee2 = new Employee("b", "1", "A");System.out.println(employee1.equals(employee2));}@EqualsAndHashCode@AllArgsConstructorprivate static class Person {private final String name;private final String identity;}@EqualsAndHashCode(callSuper = true)private static class Employee extends Person {private String company;public Employee(String name, String identity, String company) {super(name, identity);this.company = company;}}}// 输出为:false,因为考虑了父类的name属性
@ToString
使用 @ToString 注解可以为指定类生成 toString 方法,@ToString 注解的定义如下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.SOURCE)public @interface ToString {/*** 打印输出时是否包含字段的名称*/boolean includeFieldNames() default true;/*** 打印输出的结果中是否包含父类的toString方法的返回结果*/boolean callSuper() default false;/*** 如果字段的getter方法可用,在生成的toString方法中会调用它们,否则直接访问字段。* 如果设置为true,则始终会使用直接字段访问而不会调用字段的getter方法。*/boolean doNotUseGetters() default false;/*** 如果为true,则生成的toString方法仅包含显式标记为@ToString.Include的字段和方法。* 如果为false,则默认包含所有非static字段。*/boolean onlyExplicitlyIncluded() default false;/*** 如果想要在生成的toString方法中排除某字段,则通过该注解修饰对应字段*/@Target(ElementType.FIELD)@Retention(RetentionPolicy.SOURCE)public @interface Exclude {}/*** 如果想要在生成的toString方法中使用某字段,则通过该注解修饰对应字段* 需要将onlyExplicitlyIncluded设为true,来精确控制使用的字段* 如果修饰在一个方法上,则在输出中包含该方法的返回值。*/@Target({ElementType.FIELD, ElementType.METHOD})@Retention(RetentionPolicy.SOURCE)public @interface Include {// 打印顺序的优先级,首先打印更高的等级,相同等级的成员按它们在源文件中出现的顺序打印int rank() default 0;String name() default "";}}
使用示例如下:
public class ToStringDemo {public static void main(String[] args) {Employee employee = new Employee("a", "1", "A");System.out.println(employee.toString());}@ToString(onlyExplicitlyIncluded = true)@AllArgsConstructorprivate static class Person {@ToString.Include(rank = 1)private final String name;@ToString.Include(rank = 2)private final String identity;private final String other;}@ToString(includeFieldNames = false, callSuper = true)private static class Employee extends Person {private final String company;@ToString.Excludeprivate final String exclude;public Employee(String name, String identity, String company) {super(name, identity, "other");this.company = company;this.exclude = "exclude";}}}// 输出如下:ToStringDemo.Employee(super=ToStringDemo.Person(identity=1, name=a), A)
@Data
@Data 是一个复合注解,常用于普通的 POJO 类。它的功能与同时使用以下注解的效果是一样的:
@Getter@Setter@RequiredArgsConstructor@ToString@EqualsAndHashCode
@Value
@Value 注解和 @Data 注解一样也是个复合注解,但 @Value 注解常用于不可变类,它的功能与同时使用以下注解的效果是一样的:
@Getter@FieldDefaults@AllArgsConstructor@ToString@EqualsAndHashCode
可以看到 @Value 注解不会生成 setter 方法,并且构造器封装了全部属性。其中,@FieldDefaults 注解的使用方式为:@FieldDefaults(makeFinal=true, level=AccessLevel.PRIVATE),即它会把所有实例属性的访问级别修改为 private final 修饰。
@Builder
使用 @Builder 注解可以为指定类实现建造者模式,建造者模式就是一步步创建一个对象,它对用户屏蔽了里面构建的细节,但却可以精细地控制对象的构造过程。该注解可以放在类、构造函数或方法上。@Builder 注解的定义如下:
@Target({TYPE, METHOD, CONSTRUCTOR})@Retention(SOURCE)public @interface Builder {/*** 用@Default注释的字段必须有一个初始化表达式;如果在构建期间未设置该字段,则将该表达式将作为字段默认值使用。*/@Target(FIELD)@Retention(SOURCE)public @interface Default {}// 指定实体类中创建Builder的方法名称,默认为builder,一般不需要修改String builderMethodName() default "builder";// 指定Builder中用来构建实体类的方法名称,默认为build,一般不需要修改String buildMethodName() default "build";// 指定创建的建造者类的名称,默认为:实体类名+Builder后缀String builderClassName() default "";/*** 使用toBuilder可以实现以一个实例为基础继续创建一个对象,也就是可以重用原来对象的值* 但只是值复用,返回的是一个新的对象*/boolean toBuilder() default false;@Target({FIELD, PARAMETER})@Retention(SOURCE)public @interface ObtainVia {String field() default "";String method() default "";boolean isStatic() default false;}}
@Builder 注解使用示例如下:
public class BuilderDemo {@Builder(toBuilder = true)@ToStringprivate static class Person {private final String name;private final String identity;@Builder.Defaultprivate final long birthday = System.currentTimeMillis();}public static void main(String[] args) {Person person = Person.builder().name("xl").identity("123").build();System.out.println(person);person = person.toBuilder().identity("456").birthday(111).build();System.out.println(person);}}// 输出如下:BuilderDemo.Person(name=xl, identity=123, birthday=1635586221889)BuilderDemo.Person(name=xl, identity=456, birthday=111)
此外,@Builder 注解还可以配合 @Singular 注解使用,用来对集合类型的属性添加单个元素。当用 @Singular 注释一个集合字段(使用 @Builder 注释类)时,Lombok 会为该字段提供三个构建方法:
- 一个用来向集合添加单个元素
- 一个用来将另一个集合的所有元素添加到集合中
- 清空集合元素
@Builder 配合 @Singular 注解使用示例:
public class BuilderDemo2 {@Builder@ToStringprivate static class Person {@Singular("hobby")private List<String> hobby;}public static void main(String[] args) {List<String> hobby = new ArrayList<>();hobby.add("football");Person person = Person.builder().hobby(hobby).hobby("basketball")// .clearHobby().build();System.out.println(person);}}// 输入如下:BuilderDemo2.Person(hobby=[football, basketball])
日志
1. @Log
@Log 注解采用 JDK 提供的日志实现,为指定类生成一个 log 静态属性:
private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
2. @Log4j、@Log4j2
@Log4j、Log4j2 注解采用 Log4j、Log4j2 提供的日志实现,为指定类生成一个 log 静态属性:
private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
3. @CommonsLog
@CommonsLog 注解采用 Common Logging 提供的日志实现(日志接口),为指定类生成一个 log 静态属性:
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
4. @Slf4j
@Slf4j 注解采用 Slf4j 提供的日志实现(也是日志接口),为指定类生成一个 log 静态属性:
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
@Cleanup
@Cleanup 注解用于自动管理资源,用来饰局部变量,在当前变量范围内即将执行完毕退出之前会自动进行资源的清理,为变量自动生成 try-finally 这样的代码来关闭资源。
@SneakyThrows
@SneakyThrows 注解用于自动抛出受检异常,而无需在方法中使用 throw 语句显式抛出。注解定义如下:
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})@Retention(RetentionPolicy.SOURCE)public @interface SneakyThrows {// 设置你希望向上抛的异常类Class<? extends Throwable>[] value() default java.lang.Throwable.class;}
@Synchronized
@Synchronized 是同步方法修饰符的更安全的变体。与 synchronized 一样,该注解只能应用在静态和实例方法上面。它的操作类似于 synchronized 关键字,但是它锁定在不同的对象上。synchronized 关键字应用在实例方法时锁定的是 this 对象,而应用在静态方法上锁定的是类对象。对于 @Synchronized 注解声明的方法来说,它锁定的是内部生成的 $lock(实例方法)或 $Lock(静态方法)对象。@Synchronized 注解的定义如下:
@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface Synchronized {/*** 指定要锁定的对象的名称*/String value() default "";}
@Synchronized 注解使用示例:
public class SynchronizedDemo {private final Object readLock = new Object();@Synchronizedpublic static void hello() {System.out.println("world");}@Synchronizedpublic int answerToLife() {return 42;}@Synchronized("readLock")public void foo() {System.out.println("bar");}}
以上代码经过 Lombok 编译后,会生成如下代码:
public class SynchronizedDemo {private static final Object $LOCK = new Object[0];private final Object $lock = new Object[0];private final Object readLock = new Object();public SynchronizedDemo() {}public static void hello() {synchronized($LOCK) {System.out.println("world");}}public int answerToLife() {synchronized(this.$lock) {return 42;}}public void foo() {synchronized(this.readLock) {System.out.println("bar");}}}
