Automatic resource management: Call your
close()
methods safely with no hassle.
你可以使用@Cleanup
确保在代码执行后,在退出当前作用域之前自动清除给定资源。你可以通过使用@Cleanup
来注释任何局部变量声明,如下所示:
@Cleanup InputStream in = new FileInputStream(“some/file”);
因此,在局部变量作用范围的末尾,调用in.close()
。 保证通过try/finally
构造运行此调用。 请看下面的示例,看看它是如何工作的。
public class CleanUpTest {
public static void main(String[] args) throws IOException {
File file = new File("fileNameScr");
File file1 = new File("fileNameDest");
@Cleanup InputStream inputStream = new FileInputStream(file);
@Cleanup OutputStream outputStream = new FileOutputStream(file1);
byte[] bytes = new byte[1024];
int len = -1;
while (true) {
len = inputStream.read(bytes);
if (len == -1) {
break;
}
outputStream.write(bytes,0,len);
}
}
}
编译后代码如下:
public class CleanUpTest {
public static void main(String[] args) throws IOException {
File file = new File("fileNameScr");
File file1 = new File("fileNameDest");
FileInputStream inputStream = new FileInputStream(file);
try {
FileOutputStream outputStream = new FileOutputStream(file1);
try {
byte[] bytes = new byte[1024];
boolean var6 = true;
while(true) {
int len = inputStream.read(bytes);
if (len == -1) {
return;
}
outputStream.write(bytes, 0, len);
}
} finally {
if (Collections.singletonList(outputStream).get(0) != null) {
outputStream.close();
}
}
} finally {
if (Collections.singletonList(inputStream).get(0) != null) {
inputStream.close();
}
}
}
}
在finally
代码块中,发现一个很奇怪的使用方式,我们在一般在进行关闭流时,常常会这样做:
try {
// 其他操作
}finally {
if (in != null) {
in.close();
}
}
而且很搞笑的是,在lombok
的官网给出的示例,也是使用我们这种常用的方式进行关流操作的。而在实际编译后的代码中却并非如此,但是这两种操作各有什么区别呢?为什么lombok
要使用Collections.singletonList(inputStream).get(0)
种方式呢?
这一点一直没有找到准确的解释。
todo
如果要清理的对象类型没有close()
方法,而是其他一些无参数方法,则可以指定此方法的名称,如下所示:
@Cleanup(“dispose”)org.eclipse.swt.widgets.CoolBar bar = new CoolBar(parent,0);
默认情况下,清除方法假定为close()
。 不能通过@Cleanup
调用带有1个或多个参数的清理方法。
@Target(ElementType.LOCAL_VARIABLE)
@Retention(RetentionPolicy.SOURCE)
public @interface Cleanup {
// 调用的方法的名称,默认是使用 close() 方法。
// 看到方法名是字符串,就应该知道是反射实现的。
String value() default "close";
}
@Cleanup 如果清理方法抛出异常,它将吸收掉抛出方法体内的任何异常。这可能导致问题的实际原因被掩埋,因此在选择使用Project Lombok的资源管理时应该考虑这个问题。
@Cleanup
的全局配置基本上没有,仅有一个配置,是否开启@Cleanup
的使如下:
lombok.cleanup.flagUsage = [warning | error] (default: not set)
or: How I learned to stop worrying and love the
NullPointerException
.
@NonNull
was introduced in lombok v0.11.10.
你可以在方法或构造函数的参数上使用@NonNull
让lombok
为你自动生成null-check
语句。
null检查会被添加到方法的最顶层,就像下面代码所示:
if (param == null) {
throw new NullPointerException("param is marked @NonNull but is null");
}
对于构造函数而言,将在任何显式this()
或super()
调用之后,立即插入空检查。
之前说过@Setter
(如果对@Setter不了解,可以移步:)方法,并且在@Setter
注解中可以使用onParam属性为生成的所有的setter
方法的入参添加注解,现在我们刚好结合这两个注解进行测试。先来看看添加后的实体类:
@Getter
@Setter(
onParam_= {@NonNull}
)
@ToString
public class User {
private String username;
private String password;
}
// 编译后
import lombok.NonNull; // 导入依赖
public class User {
private String username;
private String password;
public User() { }
public String getUsername() { return this.username; }
public String getPassword() { return this.password; }
public void setUsername(@NonNull String username) {
if (username == null) {
throw new NullPointerException("username is marked @NonNull but is null");
} else {
this.username = username;
}
}
public void setPassword(@NonNull String password) {
if (password == null) {
throw new NullPointerException("password is marked @NonNull but is null");
} else {
this.password = password;
}
}
public String toString() {
return "User(username=" + this.getUsername() + ", password=" + this.getPassword() + ")";
}
}
此处我们着重看看两个Setter方法,在Setter方法中对我们的入参均添加了
@NonNull
注解,并且在方法体内增加了为空的验证:if (password == null) { throw new NullPointerException("password is marked @NonNull but is null"); }
但是追求细节完美的笔者,还是感觉异常信息可以自定义,或许更好。
如果lombok
为你生成所有Getter
,Setter
,hashCode
等方法以及构造函数(例如@Data
),Lombok
总是将字段上@NonNull
的各种注释视为生成空值检查的信号。 在参数上使用lombok
自己的@lombok.NonNull
会导致在您自己的方法或构造函数中插入null-check
语句,show you the code
:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@NonNull
private String username;
@NonNull
private String password;
}
// 编译后:
import lombok.NonNull;
public class User {
@NonNull
private String username;
@NonNull
private String password;
@NonNull
public String getUsername() { return this.username; }
@NonNull
public String getPassword() { return this.password; }
public void setUsername(@NonNull String username) {
if (username == null) {
throw new NullPointerException("username is marked @NonNull but is null");
} else {
this.username = username;
}
}
// toString hashCode,以及 equals 方法省略。
public void setPassword(@NonNull String password) {
if (password == null) {
throw new NullPointerException("password is marked @NonNull but is null");
} else {
this.password = password;
}
}
public User(@NonNull String username, @NonNull String password) {
if (username == null) {
throw new NullPointerException("username is marked @NonNull but is null");
} else if (password == null) {
throw new NullPointerException("password is marked @NonNull but is null");
} else {
this.username = username;
this.password = password;
}
}
}
在编译后的class文件中,所有的Getter
都在方法上添加了@NonNull
,在所有Setter
方法和带参构造方法
的所有入参添加@NonNull
注解。
# 指定抛出异常类型,当然也不是什么类型的异常都可以使用的(tips:希望后期可以支持自定义异常)
# 默认使用的是 NullPointerException
lombok.nonNull.exceptionType = [NullPointerException | IllegalArgumentException] (default: NullPointerException).
# 是否允许使用 @NonNull 注解
lombok.nonNull.flagUsage = [warning | error] (default: not set)
.
.
.
.
.
.