addSuppressed异常抑制

天涯共此时

在了解异常抑制之前,先来看看Throwable的addSuppressed()方法的注释(机翻)

将指定的异常附加到为了传递此异常而被抑制的异常。此方法是线程安全的,通常由try-with-resources语句(自动和隐式)调用。
除非通过构造函数禁用抑制行为,否则将启用抑制行为。禁用抑制后,此方法除了验证其参数外不执行其他操作。
请注意,当一个异常导致另一个异常时,通常会捕获第一个异常,然后作为响应抛出第二个异常。换句话说,两个例外之间存在因果关系。相反,在某些情况下,可能在同级代码块中引发两个独立的异常,特别是在try-with-resources语句的try块和编译器生成的finally块中,这两个异常会关闭资源。在这些情况下,只能传播所引发的异常之一。在try-with-resources语句中,当有两个这样的异常时,将传播来自try块的异常,并将finally块的异常添加到由try块的异常抑制的异常列表中。当异常展开堆栈时,它可以累积多个受抑制的异常。
异常可能抑制了异常,但也可能是由另一个异常引起的。在创建异常时,从语义上知道异常是否有原因,这与异常是否会抑制其他异常不同,后者通常仅在引发异常后才能确定。

不看也无所谓,看一下小demo就能理解了。

我们在对异常进行处理的时候,有时候在finally和catch中也会出现异常,还需要在catch或者finally中再对新的异常进行处理。可是在catch或者finally中抛出的异常会把try代码块中的异常给抑制调。但我们最需要的异常信息其实是try代码块中抛出的异常。

比如下面这个/zero的异常

@Test
public void test1() {int a;try {a = 3 / 0;System.out.println(a);} catch (ArithmeticException zero) {zero.printStackTrace();}
}
java.lang.ArithmeticException: / by zeroat com.springlearn.qiyan.base.ThrowTest.test1(ThrowTest.java:41)

我们想要在catch中处理调这个可能为0的情况,给他一个新的被除数x,现在有一个新的getX()方法去获取x。这个getX()也并不靠谱,他可能会返回null,所以我们在catch代码块中再去捕获这个新的空指针异常。

public Integer getX(){Random random = new Random();boolean b = random.nextBoolean();if(b){return null;}else{return 1;}
}@Test
public void test() {int a;Integer x = getX();try {a = 3 / 0;System.out.println(a);} catch (ArithmeticException zero) {try {a = 3 / x;System.out.println(a);} catch (NullPointerException nullPoint) {nullPoint.printStackTrace();}}
}

当getX()返回null的时候:返回的异常是NullPointerException,而不是外层的ArithmeticException

java.lang.NullPointerExceptionat com.springlearn.qiyan.base.ThrowTest.test(ThrowTest.java:26)

但是理想的状态应该是在外层的try代码块中实现对a的运算,即使出错,我们也应该去拿ArithmeticException去定位异常,空指针异常可能并不是我们想要捕获的。

这时候就可以使用Throwable中的addSuppressed方法去实现对两个异常的捕获

@Test
public void test3() {int a;Integer x = getX();try {a = 3 / 0;System.out.println(a);} catch (ArithmeticException zero) {try {a = 3 / x;System.out.println(a);} catch (NullPointerException nullPoint) {//看这里zero.addSuppressed(nullPoint);zero.printStackTrace();}}
}
java.lang.ArithmeticException: / by zeroat com.springlearn.qiyan.base.ThrowTest.test3(ThrowTest.java:85)Suppressed: java.lang.NullPointerExceptionat com.springlearn.qiyan.base.ThrowTest.test3(ThrowTest.java:89)

可以看到两个异常都被打印出来了。


这种catch或者finally中还要嵌套异常捕获的现象在对文件的处理中很常见:就比如说在finally中对外部资源进行关闭

@Test
public void test() {FileInputStream inputStream = null;try {inputStream = new FileInputStream("file.txt");} catch (FileNotFoundException e) {e.printStackTrace();} finally {if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}}
}

这样写非常繁琐,jdk7中也提供了对try-with-resource语法去简化这样复杂的代码

@Test
public void test() {try (FileInputStream inputStream = new FileInputStream("file.txt")) {System.out.println(inputStream.read());} catch (IOException e) {e.printStackTrace();}
}

看一下编译后的class文件

@Test
public void test() {try {FileInputStream inputStream = new FileInputStream("file.txt");Throwable var2 = null;try {System.out.println(inputStream.read());} catch (Throwable var12) {var2 = var12;throw var12;} finally {if (inputStream != null) {if (var2 != null) {try {inputStream.close();} catch (Throwable var11) {//看这里var2.addSuppressed(var11);}} else {inputStream.close();}}}} catch (IOException var14) {var14.printStackTrace();}}

可以看到try-with-resource也是对异常进行了addSuppressed()操作


看完了demo,我们来看一下Throwable中的addSuppressed方法

首先我们先来看一下这个方法用到的几个集合和常量

//用来标识是一个被抑制的异常
private static final String SUPPRESSED_CAPTION = "Suppressed: ";
//定义一个大小为0且不可变的集合
private static final List<Throwable> SUPPRESSED_SENTINEL =Collections.unmodifiableList(new ArrayList<Throwable>(0));
//使suppressedExceptions指向上述那个不可变的集合
private List<Throwable> suppressedExceptions = SUPPRESSED_SENTINEL;

代码:

public final synchronized void addSuppressed(Throwable exception) {//不能抑制自身if (exception == this)throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE, exception);//被抑制的异常不能为空if (exception == null)throw new NullPointerException(NULL_CAUSE_MESSAGE);//Thorwable的构造方法中可能会把suppressedExceptions设置为null,当为null时说明不启用异常抑制if (suppressedExceptions == null) // Suppressed exceptions not recordedreturn;//如果是大小为0的不可变的集合,就为suppressedExceptions重新定义为大小为1的ArrayList,并把被抑制的异常加入if (suppressedExceptions == SUPPRESSED_SENTINEL)suppressedExceptions = new ArrayList<>(1);suppressedExceptions.add(exception);
}

这个用来记录被抑制的异常的suppressedExceptions集合使用起来也很简单,只是单纯的遍历

private void printStackTrace(PrintStreamOrWriter s) {// Guard against malicious overrides of Throwable.equals by// using a Set with identity equality semantics.Set<Throwable> dejaVu =Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());dejaVu.add(this);synchronized (s.lock()) {// Print our stack traces.println(this);StackTraceElement[] trace = getOurStackTrace();for (StackTraceElement traceElement : trace)s.println("\tat " + traceElement);// Print suppressed exceptions, if any//看这里,其实就是遍历打印,getSuppressed():返回所有被try-with-resources语句抑制的异常的数组for (Throwable se : getSuppressed())se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);// Print cause, if anyThrowable ourCause = getCause();if (ourCause != null)ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);}
}

最后我们看一下Spring的bean加载过程中关于异常抑制的地方。在DefaultSingletonBeanRegistry类的getSingleton方法中(只看异常抑制相关的地方)

//用于存储被抑制的异常
@Nullable
private Set<Exception> suppressedExceptions;public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {···//判断异常抑制的集合是否为空    boolean recordSuppressedExceptions = (this.suppressedExceptions == null);//如果为空,声明为新的集合if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {//方法逻辑···} catch (IllegalStateException ex) {···} catch (BeanCreationException ex) {//遍历异常抑制集合,调用addRelatedCause方法,addRelatedCause与Throwable中的addSuppressed方法相似,就是判空与加入if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}//抛出throw ex;} finally {···}···
}

addSuppressed异常抑制相关推荐

  1. 14.PowerShell--抛出异常,错误处理

    PowerShell – 错误处理 1.  What-if 参数 (试运行,模拟操作) 简介:PowerShell 不会执行任何对系统有影响的操作,只会告诉你如果没有模拟运行,可能产生什么影响和后果. ...

  2. Effective java 系列之更优雅的关闭资源-try-with-resources

    背景: 在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在 ...

  3. eval a string with null_try-with-resources--JAVA成长之路

    JDK1.7之后,引入了try-with-resources,使得关闭资源操作无需层层嵌套在finally中,代码简洁不少,本质是一个语法糖,能够使用try-with-resources关闭资源的类, ...

  4. #华为云·寻找黑马程序员#【代码重构之路】如何优雅的关闭外部资源

    1.背景 在Java编程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在编 ...

  5. eplices如何导入外部代码_#华为云·寻找黑马程序员#【代码重构之路】如何优雅的关闭外部资源...

    1.背景 在Java编程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在编 ...

  6. try-with-resource:自动地关闭资源

    目录 一.资源关闭背景 二.JDK7之前的资源关闭方式 三.JDK7及其之后的资源关闭方式 3.1 try-with-resource语法 3.2 实现原理 3.3 异常抑制 3.4 try-with ...

  7. Java 新特性总结

    Java 新特性总结¶ 总结的这些新特性,都是自己觉得在开发中实际用得上的. 简单概括下就是: JAVA1.3:普通的原始的JAVA,基本语法相信大家都见过了 JAVA1.4:assert关键字 JA ...

  8. java7 新特性 总结版

    Java7语法新特性: 前言,这是大部分的特性,但还有一些没有写进去,比如多核 并行计算的支持加强 fork join 框架:这方面并没有真正写过和了解.也就不写进来了. 1. switch中增加对S ...

  9. 文献学习(part44)--Aberrance suppresse dspatio-temporal correlation filters for visual object tracking

    学习笔记,仅供参考,有错必纠 关键词:视觉对象跟踪:相关滤波器:时空信息:彻底的改变 Aberrance suppresse dspatio-temporal correlation filters ...

最新文章

  1. 用创新技术增进互联网广告的行业价值
  2. 构建flutter项目
  3. python编程入门经典实例-编程语言入门经典100例【Python版】
  4. rⅰd的意思_计量经济学练习题
  5. 简单的C++程序求圆的周长和面积
  6. 九个数的全排列(避免重复出现)
  7. nodejs 获取cpu核心数量_用 NodeJS 充分利用多核 CPU 的资源[每日前端夜话0xCB]
  8. 实时的毛发绘制 szlongman
  9. html5游戏制作入门系列教程(七)
  10. 金融评分卡项目—5.神经网络模型在银行业客户流失预警模型中的应用—MLP
  11. 多个excel文件合并到一个文件中的多个sheet表中
  12. Reg命令使用详解 批处理操作注册表必备
  13. 所以小学把基础的数理逻辑和ZFC集论,基数序数超滤模型论学好,大有裨益…...
  14. 大话设计模式(Java代码)
  15. 数据挖掘十大经典算法(转存)
  16. ubuntu1604安装sougou输入法
  17. win10系统要求配置_Win10 1909 系统的优点与缺点和配置要求与优化技巧
  18. Android 实现书籍翻页效果----原理篇
  19. appium 环境搭建配置清单带版本号
  20. Android targetsdkversion理解

热门文章

  1. CentOS5.5 安装Mldonkey 3.0.7
  2. MPCS-314 3A 光电耦合器 用于IGBT/MOSFET隔离栅极驱动 完美代替TLP5701
  3. Python简单实现microbit传球小游戏
  4. MIGO 收货批次增强
  5. Android Studio:增加蒙板/浮层特效
  6. 以太网阻塞的常见原因与解决方法
  7. BPR英文及中文全称
  8. 毕业四年后一次同学聚会-性格决定命运
  9. 【听】你会杀死那个胖子吗?功利与道德的选择
  10. Re6:读论文 LeSICiN: A Heterogeneous Graph-based Approach for Automatic Legal Statute Identification fro