关于@SneakyThrows使用

关于@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编译器,泛型最后存储为字节码文件时并没有泛型信息.

Guess you like

Origin blog.csdn.net/ABestRookie/article/details/120803853