Lombok 这个开源项目提供了一系列注解简化 Java 开发,帮助生成模板代码。本文对 Lombok 提供的注解进行简单的介绍。
1、@Getter/@Setter
注解使用在类变量上,帮助生成默认的 getter/setter
方法。假设字段 foo
使用了这两个注解,则命名模式为:
- 如果 foo 不是 boolean 类型,则方法会被命名为:getFoo()/setFoo();
- 如果 foo 是 boolean 类型,则方法会被命名为:isFoo()/setFoo()。
访问级别默认都是 public
,当然还可以通过 AccessLevel
来自定义,访问级别分为四种:PUBLIC
,PROTECTED
,PACKAGE
和 PRIVATE
。
2、@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
这三个注解使用在类级别上,会为类生成构造器。
@NoArgsConstructor
会生成一个没有参数的构造器,如果类有final
修饰的属性,会抛出编译时异常 —— 除非使用了@NoArgsConstructor(force = true)
;@RequiredArgsConstructor
会为所有用final
或@NonNull
修饰的属性生成一个构造器;@AllArgsConstructor
顾名思义会生成一个包含所有类变量的构造器。
3、@ToString
这个注解使用在类级别上,会为类生成 toString
方法,它有两个属性:
- callSuper:会调用父类的 toString 方法;
- includeFieldNames:在 toString 方法中会输出字段名。
4、@EqualsAndHashCode
《Effective Java》第9条建议介绍过,实现 equals
方法的同时必须实现 hashCode
方法 —— 如果不实现 hashCode
,这个类就不能与 HashMap
等基于哈希
的集合类正常工作;然而编写一个正确的 hashCode
方法是有一定难度的。
@Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof EqualsAndHashCodeExample)) return false;
EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;
if (!other.canEqual((Object)this)) return false;
if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
if (Double.compare(this.score, other.score) != 0) return false;
if (!Arrays.deepEquals(this.tags, other.tags)) return false;
return true;
}
@Override public int hashCode() {
final int PRIME = 59;
int result = 1;
final long temp1 = Double.doubleToLongBits(this.score);
result = (result*PRIME) + (this.name == null ? 43 : this.name.hashCode());
result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
result = (result*PRIME) + Arrays.deepHashCode(this.tags);
return result;
}
这个注解使用在类级别上,会为类生成 equals
和 hashCode
方法,极大地简化了程序员的工作。
5、@Cleanup
这个注解会自动调用类的 close()
方法和那一系列 try-catch
代码,用在方法的临时变量上 —— 比如输入输出流。程序员经常忘记在使用完毕之后调用 close() 方法导致内存泄漏的风险。
- value:如果没有 close() 方法,可以在
value
中指明方法名。
public class CleanupExample {
public static void main(String[] args) throws IOException {
InputStream in = new FileInputStream(args[0]); // 可用 @Cleanup 注解
try {
OutputStream out = new FileOutputStream(args[1]); // 可用 @Cleanup 注解
try {
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) break;
out.write(b, 0, r);
}
} finally {
if (out != null) {
out.close();
}
}
} finally {
if (in != null) {
in.close();
}
}
}
}
6、@NonNull
这个注解可以使用在构造器或是方法的变量
上。它会为这个变量生成一段非空检查
的代码。
public class NonNullExample extends Something {
private String name;
public NonNullExample(Person person) { // @NonNull 可以用于 person
super("Hello");
if (person == null) {
throw new NullPointerException("person");
}
this.name = person.getName();
}
}
7、@Data
这个注解用于类级别上,是一系列注解的集合:等于同时在类级别使用了 @ToString
,@EqualsAndHashCode
, @RequiredArgsConstructor
,为所有类变量上加上 @Getter
, 为所有非 final 变量加上 @Setter
。
8、@Value
和 @Data
注解类似,不同的地方在于它为类和所有类变量加上了 final
修饰 - 除非类变量已经有 @NonFinal
修饰了。
9、@Builder
这个注解使用在类级别上,它实现了《Effective Java》书中的第2条建议或者说是 Builder 模式
。
@Builder
public class BuilderExample {
private String name;
private int age;
}
相当于:
public class BuilderExample {
private String name;
private int age;
BuilderExample(String name, int age, Set<String> occupations) {
this.name = name;
this.age = age;
this.occupations = occupations;
}
public static BuilderExampleBuilder builder() {
return new BuilderExampleBuilder();
}
public static class BuilderExampleBuilder {
private String name;
private int age;
private java.util.ArrayList<String> occupations;
BuilderExampleBuilder() {
}
public BuilderExampleBuilder name(String name) {
this.name = name;
return this;
}
public BuilderExampleBuilder age(int age) {
this.age = age;
return this;
}
}
}