不要过分地细化异常
很多程序员习惯将每一条语句都分装在一个独立的try语句块中。
PrintStream out;
Stack s;
for (int i = 0; i < 100; i++) {
try {
n = s.pop();
} catch (EmptyStackException e) {
// stack was empty
}
try {
out.writeInt(n);
} catch (IOException e) {
// problem writing to file
}
}
这种编程方式将导致代码量的急剧膨胀。首先看一下这段代码所完成的任务。在这里,希望从栈中弹出 100 个数值,然后将它们存入一个文件中。如果栈是空的,则不会变成非空状态;如果文件出现错误,则也很难给予排除。出现上述问题后,这种编程方式无能为力。因此,有必要将整个任务包装在一个 try 语句块中,这样,当任何一个操作出现问题时,整个任务都可以取消。
try {
for (int i = 0; i < 100; i++) {
n = s.pop();
out.writeInt(n);
}
} catch (IOException e) {
// problem writing to file
} catch (EmptyStackException e) {
// stack was empty
}
这段代码看起来清晰多了。这样也满足了异常处理机制的其中一个目标,将正常处理与错误处理分开。
利用异常层次结构
不要只抛出 RuntimeException 异常。应该寻找更加适当的子类或创建自己的异常类。
不要只捕获 Thowable 异常,否则,会使程序代码更难读、更难维护。
考虑受查异常与非受查异常的区别。已检查异常本来就很庞大,不要为逻辑错误抛出这些异常。
早抛出,晚捕获
- 早抛出
当检测到错误的时候,有些程序员担心抛出异常。在用无效的参数调用一个方法时,返回一个虚拟的数值,还是抛出一个异常,哪种处理方式更好?例如,当栈空时,Stack.pop 是返回一个 null ,还是抛出一个异常?我们认为:在出错的地方抛出一个 EmptyStackException 异常要比在后面抛出一个 NullPointerException 异常更好。
- 晚捕获
很多程序员都感觉应该捕获抛出的全部异常。如果调用了一个抛出异常的方法,例如, FileInputStream 构造器或 readLine 方法,这些方法就会本能地捕获这些可能产生的异常。其实,传递异常要比捕获这些异常更好。让高层次的方法通知用户发生了错误,或者放弃不成功的命令更加适宜。