除非万不得已,别Catch!

【编者按】作者Yegor Bugayenko是Teamed.io的软件架构师,热衷于软件质量研究和有效的项目管理方法探索。在本文中,Yegor 就「异常被捕获但并未重新抛出」这个问题进行了深入讨论,并分享了一些建议。 

对异常只捕获但并未重新抛出究竟是 anti-pattern,还是个普通而且非常流行天津seo服务的错误确实无从考究。但毫无疑问的是,在所有异常捕获代码中,它基本无处不在,正如下面这段代码: 
Java代码 
  1. try {  
  2.   stream.write(data);  
  3. catch (IOException ex) {  
  4.   ex.printStackTrace();  
  5. }  

注意:下面的代码并没有反对。 
Java代码 
  1. try {  
  2.   stream.write('X');  
  3. catch (IOException ex) {  
  4.   throw new IllegalStateException(ex);  
  5. }  

这叫做 Exception Chaining ,是一个非常有效的构造。 

那么,捕获异常并记录究竟存在什么样的问题?首先,从宏观着手,这里正在谈论的是面向对象编程——意味着需要处理的是对象。一个对象(准确的说,是它的类)应该是这个样子: 
Java代码 
  1. final class Wire {  
  2.   private final OutputStream stream;  
  3.   Wire(final OutputStream stm) {  
  4.    this.stream = stm;  
  5.  }  
  6.  public void send(final int data) {  
  7.     try {  
  8.       this.stream.write(x);  
  9.     } catch (IOException ex) {  
  10.       ex.printStackTrace();  
  11.     }  
  12.   }  
  13. }  

这里这样来应用这个类的: 
Java代码 
  1. new Wire(stream).send(1);  

看起来不错,对么?当调用 send(1) 时,并不需要担心出现 IOException ,它将在方法内部处理。同时,如果出现异常,异常信息会被记录。但是这么做的理念是完全错误的,它传承自没有异常处理的语言,比如 C。 

异常的发明是为了将整个错误处理代码从主要逻辑中移除,以此来简化设计。同时,它们不仅仅是被移走,而且被集中在一个地方——在 main() 方法中,即整个应用的入口。 

一个异常的主要目的是搜集尽可能多的错误信息并将它抛到最上层,在这里用户能够针对它做一些处理。Exception chaining 则可以帮助更多,它允许在异常抛至上层的过程中扩充错误信息。在这个过程中,实际上非常类似于每次捕获到泡泡(即异常)后,所做的只是将它添加到一个更大的泡泡中然后重新抛出。当它到达最高层的时候,那里就有许多泡泡,像一个 Russian Doll,一个嵌套着另外一个。最原始的异常就是最小的那个泡泡。 

当捕获一个异常而并没有重新抛出时,等同于你捏碎了这个泡泡。其中包含的大量信息,包括最原始的异常和所有其它带有信息的泡泡,都被你牢牢的抓在手中。你杜绝为上层呈现它,同时你如何处理和使用上层也毫无察觉。这一切都像是暗箱操作,一些潜在的重要信息被隐藏。 

因此,在这里直接导致的是 send() 方法无法得到信任,同样基于 send() 方法的操作也无法得到信任,对象之间的信任链被破坏殆尽。这里的建议是尽可能少捕获异常,同时一旦捕获则必须抛出。 

不幸的是,Java 在很多地方的设计违背了这个原则。例如,Java 有需检查和不需检查的异常两类,但是在我看来,只应该有需检查的异常(这些异常必须被捕获或者声明为 throwable)。而且,Java 允许在一个方法中将多个异常类型声明为 throwable ——这是另一个错误;坚持只声明一种类型。在层次结构的顶部有一个通用的 Exception 类,在我看来也是错误的。除此之外,一些内置的类不允许抛出任何需检查的异常,比如说Runnable.run()。Java 还有许多关于异常的问题。 

但是尝试记住这些原则,你的代码将会更加整洁:catch 除非你别无选择。 

P.S.这个类应该是这个样子: 
Java代码 
  1. final class Wire {  
  2.   private final OutputStream stream;  
  3.   Wire(final OutputStream stm) {  
  4.     this.stream = stm;  
  5.   }  
  6.   public void send(final int data)  
  7.     throws IOException {  
  8.     this.stream.write(x);  
  9.   }  
  10. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值