关于 npe 的一个小记忆点

Java 中最常见的一类问题或者说异常就是 NullPointerException,而往往这种异常我们在查看日志的时候都是根据打印出来的异常堆栈找到对应的代码以确定问题,但是有一种情况会出现一个比较奇怪的情况,虽然我们在日志中打印了异常

1
log.error("something error", e);

这样是可以打印出来日志,譬如 slf4j 就可以把异常作为最后一个参数传入

1
void error(String var1, Throwable var2);

有的时候如果不小心把异常通过占位符传入就可能出现异常被吞的情况,不过这点不是这次的重点
即使我们正常作为最后一个参数传入了,也会出现只打印出来

1
something error, java.lang.NullPointerException: null

这样就导致了如果我们这个日志所代表的异常包含的代码范围比较大的话,就不确定具体是哪一行出现的异常,除非对这些代码逻辑非常清楚,这个是为什么呢,其实这也是 jvm 的一种优化机制,像我们目前主要还在用的 jdk8中使用的 jvm 虚拟机 hotspot 的一个热点异常机制,对于这样一直出现的相同异常,就认为是热点异常,后面只会打印异常名,不再打印异常堆栈,这样对于 io 性能能够提供一定的优化保证,这个可以通过 jvm 启动参数
-XX:-OmitStackTraceInFastThrow 来关闭优化,这个问题其实在一开始造成了一定困扰,找不准具体是哪一行代码,不过在知道这个之后简单的重启也能暂时解决问题。