-
Notifications
You must be signed in to change notification settings - Fork 1
@SneakyThrows
@SneakyThrows
可用于偷偷抛出已检查的异常,而无需在方法的 throws
子句中实际声明这一点。当然,应该谨慎使用这种有争议的能力。 lombok生成的代码不会忽略,包装,替换或以其他方式修改抛出的已检查异常;它只是欺骗了编译器。在JVM(类文件)级别上,无论方法的throws子句如何,所有检查与否的异常都可以被抛出,这就是SneakyThrows工作的原理。
当你想要选择退出已检查的异常机制时,常见的用例围绕两种情况:
- 一个不必要的严格接口,例如
Runnable
- 无论是否传播出run()
方法,检查与否,它都将被传递给Thread的(未处理异常处理程序。捕获已检查的异常和将其包装在某种RuntimeException
中只会模糊问题的真正原因。 - 一个'不可能'的异常。例如,
new String(someByteArray, "UTF-8");
声明它可以抛出UnsupportedEncodingException
,但是根据JVM规范,UTF-8必须始终可用。这里的UnsupportedEncodingException
与使用String对象时的ClassNotFoundError
差不多,你也没有必要捕获这些不可能的异常!
请注意,直接捕获偷偷抛出的已检查类型是不可能的,因为javac不允许你为try体中没有方法声明抛出的异常类型编写对应的catch块。这个问题与上面列出的任何一个用例都没有关系,所以让这个作为警告,你不应该在没有经过深思熟虑的情况下使用 @SneakyThrows
机制!
你可以将任意数量的异常传递给 @SneakyThrows
注解。如果你没有传递任何例外,你可以偷偷地抛出任何异常。
import lombok.SneakyThrows;
public class SneakyThrowsExample implements Runnable {
@SneakyThrows(UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, "UTF-8");
}
@SneakyThrows
public void run() {
throw new Throwable();
}
}
import lombok.Lombok;
public class SneakyThrowsExample implements Runnable {
public String utf8ToString(byte[] bytes) {
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw Lombok.sneakyThrow(e);
}
}
public void run() {
try {
throw new Throwable();
} catch (Throwable t) {
throw Lombok.sneakyThrow(t);
}
}
}
lombok.sneakyThrows.flagUsage
= [ warning
| error
](默认:未设置)
如果已配置,Lombok会将 @SneakyThrows
的任何用法标记为警告或错误。
因为@SneakyThrows
是一个实现细节的一部分而不是方法签名的一部分,所以当你不调用任何抛出异常的方法时,你试图将此异常在 @SneakyThrows
中声明是会报错的。 (这样做对于 throws
语句来说非常合法,以适应子类)。同样地, @SneakyThrows
不会继承。
对于人群中的不同说法者:开箱即用,Eclipse将为未捕获的异常提供“快速修复”,这些异常在try块中使用 e.printStackTrace()
包含有问题的语句。与仅仅偷偷抛出异常相比,这是非常无效的,Roel和Reinier认为被检查的异常系统远非完美,因此有理由选择退出机制。
如果将 @SneakyThrows
放在构造函数上,则任何对兄弟或父类构造函数的调用都会排除 @SneakyThrows
处理。这是我们无法解决的java限制:对兄弟/超级构造函数的调用必须是构造函数中的第一个语句;它们不能放在 try / catch 块中。
@SneakyThrows
对一个空方法,或一个空的构造函数或只调用兄弟/父类构造函数导致没有try / catch块和警告。