Java之Throwable.addSuppressed()是什么

学习使用Java7新语法try-with-resources,在查看编译文件时,接触到addSuppressed()方法。

addSuppressed()是什么?

传递被抑制的异常,便于开发者找到bug报错点。

特此记录测试理解过程:


资源类:【特意加了异常,以便测试】

public class Panda implements AutoCloseable{
    public Panda(){
        System.out.println("Panda was born");
    }
    @Override
    public void close() throws Exception {
        System.out.println("Panda is closed");
        throw new Exception("panda.close() 的异常");
    }
    public void play() throws Exception {
        System.out.println("Panda is playing");
        throw new Exception("panda.play() 的异常");
    }
}

使用try-with-resources的测试类:

public class Test {
    public static void main(String[] args) throws Exception {
        try (Panda panda = new Panda()) {
            panda.play();
            System.out.println("Over");
        } catch (Exception e) {
            throw new Exception(e);
        } finally {
            System.out.println("Finally!");
        }
    }
}

测试结果:

Panda was born
Panda is playing
Panda is closed
Finally!
Exception in thread "main" java.lang.Exception: java.lang.Exception: panda.play() 的异常
	at com.example.Test.main(Test.java:13)
Caused by: java.lang.Exception: panda.play() 的异常
	at com.example.Panda.play(Panda.java:21)
	at com.example.Test.main(Test.java:10)
	Suppressed: java.lang.Exception: panda.close() 的异常
		at com.example.Panda.close(Panda.java:16)
		at com.example.Test.main(Test.java:12)

如结果所示,play()时报错,“Over”不打印,依旧会执行close(),最后执行finally块代码,“Finally”打印。这是try-with-resources语法的特性。

查看测试类的class文件:

public class Test {
    public Test() {
    }

    public static void main(String[] args) throws Exception {
        try {
            Panda panda = new Panda();
            Throwable var2 = null;

            try {
                panda.play();
            } catch (Throwable var20) {
                var2 = var20;
                throw var20;
            } finally {
                if (panda != null) {
                    if (var2 != null) {
                        try {
                            panda.close();
                        } catch (Throwable var19) {
                            var2.addSuppressed(var19);
                        }
                    } else {
                        panda.close();
                    }
                }

            }
        } catch (Exception var22) {
            throw new Exception(var22);
        } finally {
            System.out.println("Finally!");
        }

    }
}

try-with-resources语法底层还是try-catch-finally,那么和传统的try-catch-finally方法又有什么区别呢?

区别就是第21行的addSuppressed()方法,用传统的try-catch-finally来比对测试下:

public class Test {
    public static void main(String[] args) throws Exception {
        Panda panda = null;
        try {
            panda = new Panda();
            panda.play();
            System.out.println("Over");
        } catch (Exception e) {
            throw new Exception(e);
        } finally {
            if (panda != null) {
                panda.close();
            }
            System.out.println("Finally");
        }
    }
}

测试结果:

Panda was born
Panda is playing
Panda is closed
Exception in thread "main" java.lang.Exception: panda.close() 的异常
	at com.example.Panda.close(Panda.java:16)
	at com.example.Test.main(Test.java:18)

  依结果可见,play()抛了异常,没有打印“over”,之后又执行了finally块的close(),这里也抛了异常,所以“Finally”也未打印,且控制台只打印了close()的异常。


以上可得,除了代码执行顺序之外,两者最大差别就是异常的显隐问题了。这就是addSuppressed()的作用。那么其原理为何呢?


我们来分析下:
传统的try-catch-finally代码:
  catch抛出play()产生的异常A,然后代码控制权跳转到finally块,close()又产生新异常B,然后控制权跳转调用栈的上一层方法直接抛出异常B,抑制屏蔽了异常A。

那么addSuppressed()呢?先来看看此方法的注释:

Appends the specified exception to the exceptions that were suppressed in order to deliver this exception.【将指定的异常附加到为传递此异常而抑制的异常上。】

这翻译很拗口,通俗点讲,就是在被抑制的play()的异常A上 附加close()的异常B 一起传递出去。
为什么AB的关系是这样呢?
当然是为了第一眼找到报错的位置呀~

例如:上面try-with-resources测试类的报错

Exception in thread "main" java.lang.Exception: java.lang.Exception: panda.play() 的异常
	at com.example.Test.main(Test.java:13)
Caused by: java.lang.Exception: panda.play() 的异常
	at com.example.Panda.play(Panda.java:21)
	at com.example.Test.main(Test.java:10)
	Suppressed: java.lang.Exception: panda.close() 的异常
		at com.example.Panda.close(Panda.java:16)
		at com.example.Test.main(Test.java:12)

至于为什么close()异常前用了Suppressed【被抑制的】,这个就不知道了~
查看源码:

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);

    if (suppressedExceptions == null) // Suppressed exceptions not recorded
        return;

    if (suppressedExceptions == SUPPRESSED_SENTINEL)
        suppressedExceptions = new ArrayList<>(1);

    suppressedExceptions.add(exception);
}

不是特别能看懂,就大概知道原来最后得到的是一个list,所以所有的异常都被抛出了。

至此,对于Throwable.addSuppressed()方法有了一个清晰的认识。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值