2.1 Error和Exception都继承了Throwable类,在java中只有Throwable类型的实例才可以被throw和catch;
2.2 Error是正常情况下不可能出现的情况,Error可能导致程序处于不可恢复状态;如OutOfMemoryError,StackOverflowError
2.3 Exception可分为检查(checked)和不检查 (unchecked)异常;检查异常必须显示捕获或抛出,在编译期检查;如IOException
2.4 不检查异常就是运行时异常,如NullPointerException ArrayIndexOutOfBoundsException,是可以避免的逻辑错误;
2.5 异常应该遵循throw early,catch late原则,在更高层面,有了清晰的业务逻辑,可能会更清楚合适的处理方式;
2.6 try-catch代码段会产生额外的性能开销,或者换个角度说,它往往会影响JVM对代码进行优化,所以建议仅捕获有必要的代码段,尽量不要一个大的try包住整段的代码
2.7 尽量不要用异常控制代码的流程,异常比条件语句低效;
2.8 Java每实例化一个Exception,都会对当时的栈进行快照,这是一个相对比较重的操作
2.9 当我们的服务出现反应变慢、吞吐量下降的时候,检查发生最频繁的Exception也是一种思路。
2.10 请勿在try代码块中调用return、break或continue语句;
2.11 ClassNotFoundException的产生原因主要是: Java支持使用反射方式在运行时动态加载类,例如使用Class.forName方法来动态地加载类时,可以将类名作为参数传递给上述方法从而将指定类加载到JVM内存中,如果这个类在类路径中没
有被找到,那么此时就会在运行时抛出ClassNotFoundException异常。
解决该问题需要确保所需的类连同它依赖的包存在于类路径中,常见问题在于类名书写错误
NoClassDefFoundError产生的原因在于:如果JVM或者ClassLoader实例尝试加载(可以通过正常的方法调用,也可能是使用new来创建新的对象)类的时候却找不到类的定义。要查找的类在编译的时候是存在的,运行的时候却找不
到了。这个时候就会导致NoClassDefFoundError.
造成该问题的原因可能是打包过程漏掉了部分类,或者jar包出现损坏或者篡改。解决这个问题的办法是查找那些在开发期间存在于类路径下但在运行期间却不在类路径下的类。
2.12 反应式编程(Reactive
Stream),因为其本身是异步、基于事件机制的,所以出现异常情况,决不能简单抛出去;另外,由于代码堆栈不再是同步调用那种垂直的结构,这里的异常处理和日志需要更加
小心,我们看到的往往是特定executor的堆栈,而不是业务方法调用关系。对于这种情况,你有什么好的办法吗?
a.异常:这种情况下的异常,可以通过完善任务重试机制,当执行异常时,保存当前任务信息加入重试队列。重试的策略根据业务需要决定,当达到重试上限依然无法成功,记录任务执行失
败,同时发出告警。
b.日志:类比消息中间件,处在不同线程之间的同一任务,简单高效一点的做法可能是用traceId/requestId串联。有些日志系统本身支持MDC/NDC功能,可以串联相关联的日志
MDC ( Mapped Diagnostic Contexts ),它是一个线程安全的存放诊断日志的容器。
Logback设计的一个目标之一是对分布式应用系统的审计和调试。在现在的分布式系统中,需要同时处理很多的请求。如何来很好的区分日志到底是那个请求输出的呢?我们可以为每一个请求生一个logger,但是这样子最产生大量的资源浪费,并且随着请求的增多这种方式会将服务器资源消耗殆尽,所以这种方式并不推荐。
一种更加轻量级的实现是使用MDC机制,在处理请求前将请求的唯一标示放到MDC容器中如sessionId,这个唯一标示会随着日志一起输出,以此来区分该条日志是属于那个请求的。并在请求处理完成之后清除MDC容器。
2.13 当一个try后跟了很多个catch时,必须先捕获小的异常再捕获大的异常。