引言
异常机制我们再熟悉不过,在开发环境中,它非常有用。它能帮我们的程序从错锁中恢复,也能在程序奔溃的时候方便我们定位异常原因。但大家在生产环境中会不会有这种感觉:这个异常究竟应该catch处理掉呢,还是应该抛给调用方?底层抛出来的异常,究竟在哪一层处理比较好?应该抛出什么异常?
尽管我们会想,属于用户责任就应该抛给用户,但这里的边界,实际开发中很难界定。本文来回答这个问题,并且会给出异常机制相关的最佳实践。
回忆一下异常的知识。
其中:
- Error是严重的错误,例如内存耗尽,栈溢出等等,它属于非受检异常
- RuntimeException是运行时异常,它也是非受检异常。它的子类非常常用,也非常丰富,例如非法参数异常,空指针异常等等
- 其他的就属于受检异常了,例如常见的IO,文件异常等
69. 异常只用于异常情况
异常是为了异常情况而设计的,不用将它们用于控制流,尽量不要强迫API用户为了正常控制流程而使用异常。
为什么呢?主要是性能问题:
- 异常就是为少数异常情况设计的,所以JVM并不会有太多优化
- try-catch的性能比较差,而且会阻止优化
- 试图用异常来减少流程控制的检查开销是没有必要的,因为后者加持优化后,不一定需要大量检查,总之性能要好的多
异常不要用于流程控制
来看一个案例,代码试图使用异常机制来减少每次循环的检查,但这种完全是南辕北辙。
// Horrible abuse of exceptions. Don't ever do this!
try {
int i = 0;
while(true)
range[i++].climb();
} catch (ArrayIndexOutOfBoundsException e) {
}
// 正常流程控制
for (Mountain m : range)
m.climb();
避免非必要受检异常的方法
本建议的后半句,“不要强迫API用户为了正常控制流程而使用异常”,需要一个正面的案例来说明:
for (Iterator<Foo> i = collection.iterator(); i.hasNext(); ) {
Foo foo = i.next();
..<