Lombok使用指南(中)
4、对象创建相关注解
4.1、NoArgsConstructor
@NoArgsConstructor注解只能修饰类,用于产生无参构造方法。如果只有这一个注解,并没有什么作用,因为类本身就具有无参构造方法:
@NoArgsConstructor
public class User {private int id;private String name;
}
属性:
-
access:设置构造方法的访问级别,值是 lombok.AccessLevel 枚举类型,默认是PUBLIC,在@Setter注解中介绍过。
-
staticName:设置值(非空字符串)之后,会产生一个private构造方法,同时产生一个静态方法用于返回该类的实例,方法名即为属性 staticName 的值,使用方式如下:
@NoArgsConstructor(staticName = "getInstance")
public class User {private int id;private String name;
}
产生的源码如下:
public class User {private int id;private String name;@Generatedprivate User() {}@Generatedpublic static User getInstance() {return new User();}
}
- onConstructor:在产生的构造方法上增加指定的注解
- force:强制初始化所有未赋值的 final 字段,默认值与类中属性的默认值一致,例如:
@NoArgsConstructor(force = true)
public class User {private final int id;private String name;
}
上面的类中,final 修饰的属性id没有赋初始值,本来会有编译错误,但是使用了force=true之后,产生的代码如下:
public class User {private final int id = 0; // 为id赋初始值0private String name;
}
4.2、AllArgsConstructor注解
AllArgsConstructor 注解只能修饰类,用于产生带所有属性的构造方法
属性:
-
access:与@Setter中介绍的使用方式相同。
-
staticName:与@NoArgsConstructor中的staticName属性类似;直接看使用方式及效果:
@AllArgsConstructor(staticName = "getInstance")
public class User {private int id;private String name;
}
产生的源码如下:
public class User {private int id;private String name;@Generatedprivate User(int id, String name) {this.id = id;this.name = name;}@Generatedpublic static User getInstance(int id, String name) {return new User(id, name);}
}
最终产生了一个带两个参数的私有构造方法,产生了一个指定名称的静态方法,同样带两个该参数,并通常产生的构造方法返回一个实例。
- onConstructor:在产生的构造方法上增加指定的若干注解
4.3、RequiredArgsConstructor注解
@RequiredArgsConstructor注解只能修饰类,用于产生带有必须参数的构造方法,所谓必须参数是final修饰的或使用@notNull注解修饰的属性。例如:
@RequiredArgsConstructor
public class User {private final int id;@NonNullprivate String name;private String desc;
}
产生的源码如下:
public class User {private final int id;private @NonNull String name;private String desc;@Generatedpublic User(int id, @NonNull String name) {if (name == null) {throw new NullPointerException("name is marked non-null but is null");} else {this.id = id;this.name = name;}}
}
可以看到产生的源码中,构造方法的参数只有id与name,内部还对引用类型name做了非空检查。
属性:access、staticName、onConstructor 与之前注解中的属性用法相同。
4.4、Data注解
@Date注解修饰类,作用相当于同时使用了以下注解:@Getter、@Setter、@RequiredArgsConstructor、@ToString、@EqualsAndHashCode。不过都是它们的默认效果,无法为它们单独设置属性。
属性:
- staticConstructor:与@NoArgsConstructor注解中staticName属性类似,会产生一个private的无参构造方法,同时产生一个以该属性值为名称的静态方法,用于返回一个实例。
@Data(staticConstructor = "of")
public class User {private int id;private String name;
}
主要看一下staticConstructor的效果:
public static User of() {return new User();
}
4.5、Builder注解
@Builder注解可以修饰类,方法或构造方法;用于使用建造者设计模式产生实例。示例如下:
@Builder
public class User {private int id;private String name;
}
产生的源码如下:
public class User {private int id;private String name;@GeneratedUser(int id, String name) {this.id = id;this.name = name;}@Generatedpublic static UserBuilder builder() {return new UserBuilder();}@Generatedpublic static class UserBuilder {@Generatedprivate int id;@Generatedprivate String name;@GeneratedUserBuilder() {}@Generatedpublic UserBuilder id(int id) {this.id = id;return this;}@Generatedpublic UserBuilder name(String name) {this.name = name;return this;}@Generatedpublic User build() {return new User(this.id, this.name);}@Generatedpublic String toString() {return "User.UserBuilder(id=" + this.id + ", name=" + this.name + ")";}}
}
使用方式如下:
User user = User.builder().id(1).name("老谭").build();
通过链式调用的方式将属性进行赋值,最后使用build方法返回创建的实例。
属性:
-
access:设置产生的Builder类的访问控制级别,值是AccessLevel枚举类型,默认值是PUBLIC。
-
builderMethodName:指定内部产生builder实例的方法名称,默认是 builder
-
buildMethodName:指定Builder实例中创建实例的方法,默认是 build
-
builderClassName:指定内部Builder类的名称,默认是 Builder
-
setterPrefix:指定属性赋值方法的前缀,默认为空字符串
@Builder(setterPrefix = "set", builderMethodName = "myBuilder", buildMethodName = "myBuild", builderClassName = "MyBuilder")
public class User {private int id;private String name;
}
使用时,调用的方法名变了:
User user = User.myBuilder().setId(1).setName("老谭").myBuild();
- toBuilder:设置是否产生一个获取Builder的实例方法,默认是false,如果设置为true,则方法内部使用该实例的值进行初始化返回一个Builder实例,如:
@Generated
public MyBuilder toBuilder() {return (new MyBuilder()).setId(this.id).setName(this.name);
}
4.6、Singular注解
@Singular 可修饰属性或参数,与@Builder注解配合使用,为集合提供增单个元素的方法,所以它只能修饰集合(Collection及Map都支持):
@Builder
public class User {private int id;private String name;@Singular("addHobby")private List<String> hobbies; // 爱好@Singular("addGrade")private Map<String, Integer> grades; // 成绩,结构为:科目-分数
}
产生的源码太长,直接使用就可以理解:
User user = User.builder().id(1).name("老谭").addHobby("看球").addHobby("学习") // 增加List中的单个元素.addGrade("语文", 90) // 增加 Map中的单个键值对.addGrade("数学", 98).addGrade("英语", 95).build();
属性:
- value:用于指定产生方法的名称,若未指定且修饰的属性是复数形式,Lombok将自动以其单数形式产生方法,否则必须手动指定。比如上面我使用的属性grades是复数,则可以不指定value的值,产生的方法就是grade
- ignoreNullCollections:设置是否将null对象集合作为空集合处理,默认是 false;
产生的方法如下,实现方式是如果传入的集合参数是 null,抛出 NullPointerException:
public UserBuilder hobbies(Collection<? extends String> hobbies) {if (hobbies == null) {throw new NullPointerException("hobbies cannot be null");} else {if (this.hobbies == null) {this.hobbies = new ArrayList();}this.hobbies.addAll(hobbies);return this;}
}
如果将属性设置为true,如在加入用于hobbies属性上:
@Singular(value = "addHobby", ignoreNullCollections = true)
private List<String> hobbies;
则产生的方法如下,实现方式如果传入的集合参数是null,则什么也不做:
public UserBuilder hobbies(Collection<? extends String> hobbies) {if (hobbies != null) {if (this.hobbies == null) {this.hobbies = new ArrayList();}this.hobbies.addAll(hobbies);}return this;
}
4.7、With注解
@With注解修饰类或属性,用于产生withXxx形式的方法(Xxx为属性名),需要与全参构造方法配合使用。
- 修饰类:类中所有的属性每一个都产生 withXxx形式方法
- 修饰属性:只针对该属性产生 withXxx形式方法
例如:
@AllArgsConstructor
@With
public class User {private int id;private String name;
}
产生的代码如下:
public class User {private int id;private String name;@Generatedpublic User(int id, String name) {this.id = id;this.name = name;}@Generatedpublic User withId(int id) {return this.id == id ? this : new User(id, this.name);}@Generatedpublic User withName(String name) {return this.name == name ? this : new User(this.id, name);}
}
With注解的属性:
- value:设置产生方法的访问级别,AccessLevel 枚举类型,默认是 PUBLIC
- onMethod,设置产生方法前的注解
- onParam:设置产生的方法参数前的注解
4.8、Value注解
@Value修饰类,用于产生不可变对象的类,使用如下:
@Value
public class User {int id;String name;
}
产生的源码如下:
public final class User {private final int id;private final String name;@Generatedpublic User(int id, String name) {this.id = id;this.name = name;}@Generatedpublic int getId() {return this.id;}@Generatedpublic String getName() {return this.name;}@Generatedpublic boolean equals(Object o) {return true;}@Generatedpublic int hashCode() {int PRIME = 59;int result = 1;result = result * 59 + this.getId();Object $name = this.getName();result = result * 59 + ($name == null ? 43 : $name.hashCode());return result;}@Generatedpublic String toString() {return "User(id=" + this.getId() + ", name=" + this.getName() + ")";}
}
类前使用final修饰,属性为 private final 修饰且只能由构造方法为其赋值,也不提供setter方法(即时使用了 @Setter 注解)。
5、异常相关注解
5.1、SneakyThrows注解
@SneakyThrows注解修饰方法或构造方法,用于在方法体中产生异常处理代码。使用方式如下:
@SneakyThrows({ClassNotFoundException.class,SQLException.class})
public Connection getConnection() {Class.forName("com.mysql.cj.jdbc.Driver");return DriverManager.getConnection("jdbc:mysql:///mydb","root","root");
}
效果就是在方法体中使用try-catch捕获注解中value指定的异常。
属性:
- value:指定期望捕获的若干异常,默认是 Throwable.class。
5.2、Cleanup注解
@Cleanup修饰局部变量,用于变量无论发生什么情况都会通过调用其 close 方法进行清理。通过将本地变量声明之后到您的作用域结束的所有语句都包裹在一个 try 块中来实现,该块在 finally 操作中关闭资源。
public void copyFile(String src, String dest) throws IOException {@CleanupFileInputStream inStream = new FileInputStream(src);@CleanupFileOutputStream outStream = new FileOutputStream(dest);byte[] b = new byte[2028];int len = 0;while ((len = inStream.read(b, 0, b.length)) != -1) {outStream.write(b, 0, len);}
}
产生的源码如下:
public void copyFile(String src, String dest) throws IOException {FileInputStream inStream = new FileInputStream(src);try {FileOutputStream outStream = new FileOutputStream(dest);try {byte[] b = new byte[2028];int len = 0;while((len = inStream.read(b, 0, b.length)) != -1) {outStream.write(b, 0, len);}} finally {if (Collections.singletonList(outStream).get(0) != null) {outStream.close();}}} finally {if (Collections.singletonList(inStream).get(0) != null) {inStream.close();}}
}
确保在finally子句中对@Cleanup修饰的两个变量调用了close方法进行关闭。
属性:
- value:指定清除资源所调用方法的名称,默认是close,需要注意该方法不能有任何参数