不要过分地细化异常

很多程序员习惯将每一条语句都分装在一个独立的try语句块中。

  1. PrintStream out;
  2. Stack s;
  3. for (int i = 0; i < 100; i++) {
  4. try {
  5. n = s.pop();
  6. } catch (EmptyStackException e) {
  7. // stack was empty
  8. }
  9. try {
  10. out.writeInt(n);
  11. } catch (IOException e) {
  12. // problem writing to file
  13. }
  14. }

这种编程方式将导致代码量的急剧膨胀。首先看一下这段代码所完成的任务。在这里,希望从栈中弹出 100 个数值,然后将它们存入一个文件中。如果栈是空的,则不会变成非空状态;如果文件出现错误,则也很难给予排除。出现上述问题后,这种编程方式无能为力。因此,有必要将整个任务包装在一个 try 语句块中,这样,当任何一个操作出现问题时,整个任务都可以取消。

  1. try {
  2. for (int i = 0; i < 100; i++) {
  3. n = s.pop();
  4. out.writeInt(n);
  5. }
  6. } catch (IOException e) {
  7. // problem writing to file
  8. } catch (EmptyStackException e) {
  9. // stack was empty
  10. }

这段代码看起来清晰多了。这样也满足了异常处理机制的其中一个目标,将正常处理与错误处理分开。

利用异常层次结构

不要只抛出 RuntimeException 异常。应该寻找更加适当的子类或创建自己的异常类。
不要只捕获 Thowable 异常,否则,会使程序代码更难读、更难维护。
考虑受查异常与非受查异常的区别。已检查异常本来就很庞大,不要为逻辑错误抛出这些异常。

早抛出,晚捕获

  • 早抛出
    当检测到错误的时候,有些程序员担心抛出异常。在用无效的参数调用一个方法时,返回一个虚拟的数值,还是抛出一个异常,哪种处理方式更好?例如,当栈空时,Stack.pop 是返回一个 null ,还是抛出一个异常?我们认为:在出错的地方抛出一个 EmptyStackException 异常要比在后面抛出一个 NullPointerException 异常更好。
  • 晚捕获
    很多程序员都感觉应该捕获抛出的全部异常。如果调用了一个抛出异常的方法,例如, FileInputStream 构造器或 readLine 方法,这些方法就会本能地捕获这些可能产生的异常。其实,传递异常要比捕获这些异常更好。让高层次的方法通知用户发生了错误,或者放弃不成功的命令更加适宜。