@SneakyThrows
大胆地抛出之前无人抛出过的检查型异常!
概述
@SneakyThrows
可以被用于偷偷地抛出检查型异常,而无需在您的方法的 throws
子句中实际声明它。当然,这种有争议的能力应该谨慎使用。lombok 生成的代码不会忽略、包装、替换或以其他方式修改抛出的检查型异常;它只是欺骗了编译器。在 JVM(类文件)级别,所有异常,无论是否检查,都可以被抛出,而无需考虑您方法的 throws
子句,这就是它工作的原因。
当您想要选择退出检查型异常机制时,常见的用例围绕以下两种情况:
- 不必要的严格接口,例如
Runnable
- 无论什么异常从您的run()
方法中传播出来,无论是否检查,它都将被传递给Thread
的未处理异常处理程序。捕获检查型异常并将其包装在某种RuntimeException
中只会模糊问题的真正原因。 - “不可能”的异常。例如,
new String(someByteArray, "UTF-8");
声明它可以抛出UnsupportedEncodingException
,但根据 JVM 规范,UTF-8 *必须* 始终可用。此处的UnsupportedEncodingException
与您使用 String 对象时的ClassNotFoundError
一样不可能发生,而且您也不会捕获后者!
当使用 lambda 语法(arg -> action
)时,受到不必要的严格接口的约束尤其常见;然而,lambda 无法被注解,这意味着将 @SneakyThrows
与 lambda 结合使用并不容易。
请注意,不可能 直接捕获偷偷抛出的检查型类型,因为 javac 不会让您为 try 代码块中没有方法调用声明抛出的异常类型编写 catch 代码块。这个问题与上面列出的任何用例都不相关,因此请以此作为警告,您不应在没有经过深思熟虑的情况下使用 @SneakyThrows
机制!
您可以将任意数量的异常传递给 @SneakyThrows
注解。如果您不传递任何异常,您可以偷偷地抛出任何异常。
使用 Lombok
import lombok.SneakyThrows;
|
原生 Java
import lombok.Lombok;
|
支持的配置键
-
lombok.sneakyThrows.flagUsage
= [warning
|error
] (默认值:未设置) - 如果配置,Lombok 将把任何
@SneakyThrows
的使用标记为警告或错误。
小字声明
因为 @SneakyThrows
是一个实现细节,而不是您方法签名的一部分,所以如果您尝试将检查型异常声明为偷偷抛出,但您没有调用任何抛出此异常的方法,则会发生错误。(对于 throws
语句为了适应子类这样做是完全合法的)。同样,@SneakyThrows
不会继承。
对于人群中的反对者:开箱即用,Eclipse 将为未捕获的异常提供“快速修复”,该修复将冒犯性语句包装在 try/catch 代码块中,catch 代码块中只有 e.printStackTrace()
。与偷偷地将异常向上传递相比,这是非常没有效率的,因此 Roel 和 Reinier 认为他们完全有理由声称检查型异常系统远非完美,因此有必要采用选择退出机制。
如果您将 @SneakyThrows
放在构造函数上,则对同级或超类构造函数的任何调用都将排除在 @SneakyThrows
处理之外。这是一个我们无法解决的 java 限制:对同级/超类构造函数的调用必须是构造函数中的第一个语句;它们不能放在 try/catch 代码块内。
空方法上的 @SneakyThrows
,或为空或仅调用同级/超类构造函数的构造函数会导致没有 try/catch 代码块并发出警告。