小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
关于@SneakyThrows注解的使用,主要是消除代码中异常处理代码.
1 异常引入
Java中异常Throwable分为两类, 一种是Exception类,称为受检异常(Checked Exception), 第二种是RuntimeException类, 运行时异常.
Exception类异常,强制要求方法抛出可能出现的异常,调用者必须处理这个异常. 一般在代码中,程序员通过捕获异常,再包一层RuntimeException,向外抛出.(常见如Spring源码中)
2 @SneakyThrows
1 SneakyThrows注解的源码
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.SOURCE)
public @interface SneakyThrows {
/** @return The exception type(s) you want to sneakily throw onward. */
Class<? extends Throwable>[] value() default java.lang.Throwable.class;
//The fully qualified name is used for java.lang.Throwable in the parameter only. This works around a bug in javac:
// presence of an annotation processor throws off the type resolver for some reason.
}
复制代码
2使用案例
public class SneakyThrowDemo {
// 方法主动声明可能出现的异常
public void test1() throws IllegalAccessException, InstantiationException {
SneakyThrowDemo sneakyThrowDemo = SneakyThrowDemo.class.newInstance();
}
// 使用SneakyThrows注解
@SneakyThrows
public void test2() {
SneakyThrowDemo sneakyThrowDemo = SneakyThrowDemo.class.newInstance();
}
// test2方法的编译结果
public void test3() {
try {
SneakyThrowDemo sneakyThrowDemo = SneakyThrowDemo.class.newInstance();
} catch (Throwable e) {
// 调用Lombok方法转化为RuntimeException
throw Lombok.sneakyThrow(e);
}
}
}
复制代码
其中Lombok.sneakyThrow()方法
/**
* Throws any throwable 'sneakily' - you don't need to catch it, nor declare that you throw it onwards.
* The exception is still thrown - javac will just stop whining about it.
* <p>
* Example usage:
* <pre>public void run() {
* throw sneakyThrow(new IOException("You don't need to catch me!"));
* }</pre>
* <p>
* NB: The exception is not wrapped, ignored, swallowed, or redefined. The JVM actually does not know or care
* about the concept of a 'checked exception'. All this method does is hide the act of throwing a checked exception
* from the java compiler.
* <p>
* Note that this method has a return type of {@code RuntimeException}; it is advised you always call this
* method as argument to the {@code throw} statement to avoid compiler errors regarding no return
* statement and similar problems. This method won't of course return an actual {@code RuntimeException} -
* it never returns, it always throws the provided exception.
*
* @param t The throwable to throw without requiring you to catch its type.
* @return A dummy RuntimeException; this method never returns normally, it <em>always</em> throws an exception!
*/
public static RuntimeException sneakyThrow(Throwable t) {
if (t == null) throw new NullPointerException("t");
return Lombok.<RuntimeException>sneakyThrow0(t);
}
// 对返回参数做了强转为T类型
private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T {
throw (T)t;
}
复制代码
整个处理过程中, 最重要的是throw (T)t
, 使用泛型,将传入的Throwable强转为RuntimeException异常.
虽然, 我们抛出的异常不是RuntimeException,但是可以骗过javac编译器,泛型最后存储为字节码文件时并没有泛型信息.
近期评论