原文地址:https://dzone.com/articles/catch-me-if-you-cant-do-otherwise

I don't know whether it's an anti-pattern or just a common and very popular mistake, but I see it everywhere and simply must write about it. I'm talking about exception catching without re-throwing. I'm talking about something like this Java code:

 
try {
  stream.write(data);
} catch (IOException ex) {
  ex.printStackTrace();
}

©Catch Me If You Can (2002) by Steven Spielberg

Pay attention: I don't have anything against this code:

try {
  stream.write('X');
} catch (IOException ex) {
  throw new IllegalStateException(ex);

This is called exception chaining and is a perfectly valid construct.

So what is wrong with catching an exception and logging it? Let's try to look at the bigger picture first. We're talking about object-oriented programming — this means we're dealing with objects. Here is how an object (its class, to be exact) would look:

final class Wire {
  private final OutputStream stream;
  Wire(final OutputStream stm) {
    this.stream = stm;
  }
  public void send(final int data) {
    try {
      this.stream.write(x);
    } catch (IOException ex) {
      ex.printStackTrace();
    }
  }
}
 

Here is how I'm using this class:

new Wire(stream).send(1);

Looks nice, right? I don't need to worry about that IOException when I'm calling send(1). It will be handled internally, and if it occurs, the stacktrace will be logged. But this is a totally wrong way of thinking, and it's inherited from languages without exceptions, like C.

Exceptions were invented to simplify our design by moving the entire error handling code away from the main logic. Moreover, we're not just moving it away but also concentrating it in one place — in themain() method, the entry point of the entire app.

The primary purpose of an exception is to collect as much information as possible about the error and float it up to the highest level, where the user is capable of doing something about it. Exception chaining helps even further by allowing us to extend that information on its way up. We are basically putting our bubble (the exception) into a bigger bubble every time we catch it and re-throw. When it hits the surface, there are many bubbles, each remaining inside another like a Russian doll. The original exception is the smallest bubble.

When you catch an exception without re-throwing it, you basically pop the bubble. Everything inside it, including the original exception and all other bubbles with the information inside them, are in your hands. You don't let me see them. You use them somehow, but I don't know how. You're doing something behind the scenes, hiding potentially important information.

If you're hiding that from me, I can't promise my user that I will be honest with him and openly report a problem when it occurs. I simply can't trust your send() method anymore, and my user will not trust me.

By catching exceptions without re-throwing them, you're basically breaking the chain of trust between objects.

My suggestion is to catch exceptions as seldomly as possible, and every time you catch them, re-throw.

Unfortunately, the design of Java goes against this principle in many places. For example, Java has checked and un-checked exceptions, while there should only be checked ones in my opinion (the ones you must catch or declare as throwable). Also, Java allows multiple exception types to be declared as throwable in a single method — yet another mistake; stick to declaring just one type. Also, there is a generic Exception class at the top of the hierarchy, which is also wrong in my opinion. Besides that, some built-in classes don't allow any checked exceptions to be thrown, like Runnable.run(). There are many other problems with exceptions in Java.

But try to keep this principle in mind and your code will be cleaner: catch only if you have no other choice.

P.S. Here is how the class should look:

final class Wire {
  private final OutputStream stream;
  Wire(final OutputStream stm) {
    this.stream = stm;
  }
  public void send(final int data)
    throws IOException {
    this.stream.write(x);
  }
}
 
 

Catch Me If You ... Can't Do Otherwise--转载的更多相关文章

  1. UDPClient的用法

    UDP_Server: UdpClient receivingUdpClient = ); IPEndPoint RemoteIpEndPoint = ); try { byte[] sdata = ...

  2. Java编程思想学习(九) 异常处理

    java的异常处理机制可以使程序有极好的容错性,让程序更加的健壮.所谓的异常,就是指的阻止当前方法或作用域继续执行的问题,,当程序运行时出现异常时,系统就会自动生成一个Exception对象来通知程序 ...

  3. C#中DataTable与实体集合通用转换(使用扩展方法)

    本案例提供了:把DataRow转换为单个实体.dataTable转换为List泛型支持时间格式转换. 下文的方法都是扩展方法.扩展方法要求写在静态类中,方法也要静态. 它必须在一个非嵌套.非泛型的静态 ...

  4. Android Studio经常使用操作技巧(不断更新)

    这段时间一直在用Android Studio做一些Demo的开发.一開始从Eclipse中转向这个开发工具,各种不适应,希望此博文能够一直更新.还有网友能够分享出自己方便更好更快开发的一些技巧. 首先 ...

  5. jdbc批量插入

    分享牛,分享牛原创.有这样一个需求,文本文件中的数据批量的插入mysql,怎么用jdbc方式批量插入呢? jdbc默认提供了批量插入的方法,可能用一次就忘记了,这里做笔记记录一下jdbc批量插入吧. ...

  6. Java IO流学习总结四:缓冲流-BufferedReader、BufferedWriter

    在上一篇文章中Java IO流学习总结三:缓冲流-BufferedInputStream.BufferedOutputStream介绍了缓冲流中的字节流,而这一篇着重介绍缓冲流中字符流Buffered ...

  7. C# p2p UDP穿越NAT,UDP打洞源码

    思路如下(参照源代码): 1. frmServer启动两个网络侦听,主连接侦听,协助打洞的侦听. 2. frmClientA和frmClientB分别与frmServer的主连接保持联系. 3. 当f ...

  8. Spring 事物传播特性

    Spring 事物传播特性 这是Spring官方的定义 一共有7种 摘自源码省略了一部分 public interface TransactionDefinition { int PROPAGATIO ...

  9. java当中JDBC当中请给出一个Oracle DataSource and SingleTon例子

    [学习笔记] 6.Oracle DataSource and SingleTon: import oracle.jdbc.pool.OracleDataSource;import java.sql.C ...

  10. SQL数据库—<7>事务、异常和游标

    事务 一.什么是事务能够保证数据的一致性的代码控制,要么执行提交,要么滚回事务的初始状态 二.事务的四大特性:ACIDA:原子性-------事务不可拆开,要么执行要么回滚无中间状态C:一致性---- ...

随机推荐

  1. [Teamcenter 2007 开发实战] 调用web service

    前言 在TC的服务端开发中, 能够使用gsoap 来调用web service. 怎样使用 gsoap  , 參考 gsoap 实现 C/C++ 调用web service 接下来介绍怎样在TC中进行 ...

  2. psycopg2 ImportError: DLL load failed

    setup.py install 报错  error: command 'mt.exe' failed: No such file or directory  或者 Unable to find vc ...

  3. HDU 3001 三进制状压DP

    N个城市,M条道路,每条道路有其经过的代价,每一个城市最多能够到达两次,求走全然部城市最小代价,起点随意. 三进制状压.存储每一个状态下每一个城市经过的次数. 转移方程: dp[i+b[k]][k]= ...

  4. 怎样安装Windows7操作系统

     1. 打开电脑,插入Windows7安装光盘. 2. 又一次启动电脑: 3. 依据提示按下对应的键.进入选择启动项菜单选择光驱引导.在"Boot Menu"界面按键盘上下键选 ...

  5. Docker -- 系统整洁之道 -- 1

    在上文Docker – 系统整洁之道 – 0中已经对Docker是什么,安装Docker以及怎么运行一个简单的容器有了初步了解,这篇文章介绍Docker的一些命令和Docker镜像的使用及操作. 一些 ...

  6. OpenGL编程逐步深入(三)在窗口中显示一个三角形

    这一节教程的内容会比较少,我们仅仅是对上一节教程中的代码进行扩展,在窗口中渲染一个三角形出来. 本节我们以下图所示正方形来讲解OpenGl中的坐标系统.当沿着Z轴负方向看时,可见顶点的坐标必须在这个正 ...

  7. 11.2.0.1升级到11.2.0.4报错之中的一个:UtilSession failed: Patch 9413827

    UtilSession failed: Patch 9413827 requires component(s) that are not installed in OracleHome. These ...

  8. 对string的一些扩展函数

    对string作了一些扩展,包含string转化为int.string转化为double.string转化为bool.打印系统当前时间.但没有解决数据溢出的问题,请大神帮忙解决! //头文件 /*pa ...

  9. CCNA Cloud CLDFND 210-451 QUIZ: Server Virtualization

    Author:海峰 http://weibo.com/344736086 http://yanheven.github.io/ http://blog.csdn.net/yanheven1 1.Whi ...

  10. elasticsearch index 之 engine

    elasticsearch对于索引中的数据操作如读写get等接口都封装在engine中,同时engine还封装了索引的读写控制,如流量.错误处理等.engine是离lucene最近的一部分. engi ...