@SneakyThrows注解
-
@SneakyThrows注解的用途得从java的异常设计体系说起
-
这是异常的类图
-
Throwable是Error和Exception的父类,用来定义所有可以作为异常被抛出来的类。 UML图如下:
-
Error和Exception区分:
-
Error是编译时错误和系统错误,系统错误在除特殊情况下,都不需要你来关心,基本不会出现。而编译时错误,如果你使用了编译器,那么编译器会提示。
-
Exception则是可以被抛出的基本类型,我们需要主要关心的也是这个类。
-
Exception又分为RunTimeException和其他Exception。
RunTimeException和其他Exception区分:
-
其他Exception,受检查异常。可以理解为错误,必须要开发者解决以后才能编译通过,解决的方法有两种
-
throw到上层
-
try-catch处理
-
-
RunTimeException:运行时异常,又称不受检查异常,不受检查,因为不受检查,所以在代码中可能会有RunTimeException时Java编译检查时不会告诉你有这个异常,但是在实际运行代码时则会暴露出来,比如经典的1/0,空指针等。如果不处理也会被Java自己处理
@SneakyThrows的作用:
-
普通Exception类,也就是我们常说的受检异常或者Checked Exception会强制要求抛出它的方法声明throws,调用者必须显示的去处理这个异常。设计的目的是为了提醒开发者处理一些场景中必然可能存在的异常情况。比如网络异常造成IOException
-
但是现实大部分情况下的异常,我们都是一路往外抛了事。所以渐渐的java程序员处理Exception的常见手段就是外面包一层RuntimeException,接着往上丢
-
try{ }catch(Exception e){ throw new RuntimeException(e); }
-
而Lombok的@SneakyThrows就是为了消除这样的模板代码。使用注解后不需要担心Exception的处理
-
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.sneakyThrow(t);中。可能大家都会以为这个方法就是new RuntimeException()之类的。然而事实并非如此。阅读代码可以看出整个方法其实最核心的逻辑是throw (T)t;,利用泛型将我们传入的Throwable强转为RuntimeException。虽然事实上我们不是RuntimeException。但是没关系。因为JVM并不关心这个。泛型最后存储为字节码时并没有泛型的信息。这样写只是为了骗过javac编译器。源码中注释有解释
-
public static RuntimeException sneakyThrow(Throwable t) { if (t == null) throw new NullPointerException("t"); return Lombok.<RuntimeException>sneakyThrow0(t); } private static <T extends Throwable> T sneakyThrow0(Throwable t) throws T { throw (T)t; }