addSuppressed异常抑制
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异常抑制相关推荐
- 14.PowerShell--抛出异常,错误处理
PowerShell – 错误处理 1. What-if 参数 (试运行,模拟操作) 简介:PowerShell 不会执行任何对系统有影响的操作,只会告诉你如果没有模拟运行,可能产生什么影响和后果. ...
- Effective java 系列之更优雅的关闭资源-try-with-resources
背景: 在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在 ...
- eval a string with null_try-with-resources--JAVA成长之路
JDK1.7之后,引入了try-with-resources,使得关闭资源操作无需层层嵌套在finally中,代码简洁不少,本质是一个语法糖,能够使用try-with-resources关闭资源的类, ...
- #华为云·寻找黑马程序员#【代码重构之路】如何优雅的关闭外部资源
1.背景 在Java编程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在编 ...
- eplices如何导入外部代码_#华为云·寻找黑马程序员#【代码重构之路】如何优雅的关闭外部资源...
1.背景 在Java编程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制,如果我们不在编 ...
- try-with-resource:自动地关闭资源
目录 一.资源关闭背景 二.JDK7之前的资源关闭方式 三.JDK7及其之后的资源关闭方式 3.1 try-with-resource语法 3.2 实现原理 3.3 异常抑制 3.4 try-with ...
- Java 新特性总结
Java 新特性总结¶ 总结的这些新特性,都是自己觉得在开发中实际用得上的. 简单概括下就是: JAVA1.3:普通的原始的JAVA,基本语法相信大家都见过了 JAVA1.4:assert关键字 JA ...
- java7 新特性 总结版
Java7语法新特性: 前言,这是大部分的特性,但还有一些没有写进去,比如多核 并行计算的支持加强 fork join 框架:这方面并没有真正写过和了解.也就不写进来了. 1. switch中增加对S ...
- 文献学习(part44)--Aberrance suppresse dspatio-temporal correlation filters for visual object tracking
学习笔记,仅供参考,有错必纠 关键词:视觉对象跟踪:相关滤波器:时空信息:彻底的改变 Aberrance suppresse dspatio-temporal correlation filters ...
最新文章
- 用创新技术增进互联网广告的行业价值
- 构建flutter项目
- python编程入门经典实例-编程语言入门经典100例【Python版】
- rⅰd的意思_计量经济学练习题
- 简单的C++程序求圆的周长和面积
- 九个数的全排列(避免重复出现)
- nodejs 获取cpu核心数量_用 NodeJS 充分利用多核 CPU 的资源[每日前端夜话0xCB]
- 实时的毛发绘制 szlongman
- html5游戏制作入门系列教程(七)
- 金融评分卡项目—5.神经网络模型在银行业客户流失预警模型中的应用—MLP
- 多个excel文件合并到一个文件中的多个sheet表中
- Reg命令使用详解 批处理操作注册表必备
- 所以小学把基础的数理逻辑和ZFC集论,基数序数超滤模型论学好,大有裨益…...
- 大话设计模式(Java代码)
- 数据挖掘十大经典算法(转存)
- ubuntu1604安装sougou输入法
- win10系统要求配置_Win10 1909 系统的优点与缺点和配置要求与优化技巧
- Android 实现书籍翻页效果----原理篇
- appium 环境搭建配置清单带版本号
- Android targetsdkversion理解
热门文章
- CentOS5.5 安装Mldonkey 3.0.7
- MPCS-314 3A 光电耦合器 用于IGBT/MOSFET隔离栅极驱动 完美代替TLP5701
- Python简单实现microbit传球小游戏
- MIGO 收货批次增强
- Android Studio:增加蒙板/浮层特效
- 以太网阻塞的常见原因与解决方法
- BPR英文及中文全称
- 毕业四年后一次同学聚会-性格决定命运
- 【听】你会杀死那个胖子吗?功利与道德的选择
- Re6:读论文 LeSICiN: A Heterogeneous Graph-based Approach for Automatic Legal Statute Identification fro