冷知识
再给大家补充一个关于异常的冷知识吧。
还是上面这个截图。你有没有觉得有一丝丝的奇怪?
夜深人静的时候,你有没有想过这样的一个问题:
程序里面并没有打印日志的地方,那么控制台的日子是谁通过什么地方打印出来的呢?
是谁干的?
这个问题很好回答,猜也能猜到,是 JVM 帮我们干的。
什么地方?
这个问题的答案,藏在源码的这个地方,我给你打个断点跑一下,当然我建议你也打个断点跑一下:
java.lang.ThreadGroup#uncaughtException
而在这个地方打上断点,根据调用堆栈顺藤摸瓜可以找到这个地方:
java.lang.Thread#dispatchUncaughtException
看方法上的注释:
This method is intended to be called only by the JVM.
翻译过来就是:这个方法只能由 JVM 来调用。
既然源码里面都这样说了,我们可以去找找对应的源码嘛。
https://hg.openjdk.java.net/jdk7u/jdk7u/hotspot/file/5b9a416a5632/src/share/vm/runtime/thread.cpp
在 openJdk 的 thread.cpp 源码里面确实是找到了该方法被调用的地方:
而且这个方法还有个有意思的用法。
看下面的程序和输出结果:
我们可以自定义当前线程的 UncaughtExceptionHandler
,在里面做一些兜底的操作。
有没有品出来一丝丝全局异常处理机制的味道?
好了,再来最后一个问题:
我都这样问了,那么答案肯定是不一定的。
你就想想,发挥你的小脑袋使劲的想,啥情况下 try 里面的代码抛出了异常,外面的 catch 不会捕捉到?
来,看图:
没想到吧?
这样处理一下,外面的 catch 就捕捉不到异常了。
是不是很想打我。
别慌,上面这样套娃多没意思啊。
你再看看我这份代码:
public class MainTest { public static void main(String[] args) { try { ExecutorService threadPool = Executors.newFixedThreadPool(1); threadPool.submit(()->{ int a=1/0; }); } catch (Exception e) { e.printStackTrace(); } } }
你直接拿去执行,控制台不会有任何的输出。
来看动图:
是不是很神奇?
不要慌,还有更绝的。
把上面的代码从 threadPool.submit
修改为 threadPool.execute
就会有异常信息打印出来了:
但是你仔细看,你会发现,异常信息虽然打印出来了,但是也不是因为有 catch 代码块的存在。
具体是为啥呢?
参见这篇文章,我之前详细讲过的:《关于多线程中抛异常的这个面试题我再说最后一次!》
最后说一句
好了,看到了这里安排个关注吧。
感谢您的阅读,我坚持原创,十分欢迎并感谢您的关注。