@SneakyThrows
大胆抛出已检查的异常,以前没有人抛出它们!
Overview
@SneakyThrows可以用来偷偷抛出已检查的异常而不在方法的throws子句中实际声明这一点。当然,应该谨慎使用这种有争议的能力。由lombok生成的代码不会忽略,包装,替换或以其他方式修改抛出的已检查异常; 它只是伪造了编译器。在JVM(类文件)级别,无论方法的throws子句如何,都可以抛出所有异常,无论是否检查,这就是为什么这样做的原因。
当您想要选择退出已检查的异常机制时,常见的用例围绕两种情况:
一个不必要的严格的接口,例如Runnable- 无论是否传播出你的run()方法,检查与否,它都将被传递给Thread未处理的异常处理程序。捕获已检查的异常并将其包装在某种情况RuntimeException下只会模糊问题的真正原因。
一个'不可能'的例外。例如,new String(someByteArray, "UTF-8");声明它可以抛出UnsupportedEncodingException但是根据JVM规范,UTF-8 必须始终可用。一个UnsupportedEncodingException在这里大约是有可能的ClassNotFoundError,当你使用一个String对象,而你没有赶上那些要么!
请注意,直接捕获偷偷摸摸的已检查类型是不可能的,因为javac不允许您为try体中没有方法调用声明为抛出的异常类型编写catch块。此问题与上面列出的任何一个用例都无关,所以请注意这个问题,不要在@SneakyThrows没有经过深思熟虑的情况下使用该机制!
您可以将任意数量的例外传递给@SneakyThrows注释。如果你没有通过任何例外,你可以偷偷地抛出任何例外。
With Lombok
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(); } }
Vanilla Java
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); } } }
Supported configuration keys:
lombok.sneakyThrows.flagUsage = [warning | error] (default: not set)
Small print
因为@SneakyThrows是一个实现细节而不是方法签名的一部分,所以当你不调用任何抛出此异常的方法时,如果你试图将一个被检查的异常声明为偷偷抛出则是一个错误。(throws对于容纳子类的语句,这样做是完全合法的)。同样,@SneakyThrows不继承。
对于人群中的不同说法者:开箱即用,Eclipse将为未捕获的异常提供“快速修复”,这些异常包含在catch块中的try / catch块中的违规语句e.printStackTrace()。与仅仅偷偷地抛出异常相比,这是非常无效的,Roel和Reinier认为被检查的异常系统远非完美,因此有理由选择退出机制。
如果你加上@SneakyThrows一个构造函数,那么对兄弟或超级构造函数的任何调用都将被排除在@SneakyThrows处理之外。这是我们无法解决的java限制:对兄弟/超级构造函数的调用必须是构造函数中的第一个语句; 它们不能放在try / catch块中。
@SneakyThrows 在一个空方法,或一个空的构造函数或只有一个兄弟/超级构造函数的调用导致没有try / catch块和警告。