原文地址: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. ArcGIS api for javascript——创建地图

    描述 这个示例显示ArcGIS Server的一个地图.ArcGIS Server地图是缓存的,意味着它有服务器管理员建来提升性能的一组预先渲染的切片.由于这个原因地图通过ArcGISTiledMap ...

  2. Windows安装两个mysql数据库步骤

    因为新旧项目数据库版本号差距太大.编码格式不同.引擎也不同,所以仅仅好装两个数据库. 本次安装两个mysql数据库.版本号各自是4.0.18,5.5.36.都是可运行文件直接安装. 本机上之前已经安装 ...

  3. 我持续推动Rust语言支持Windows XP系统

    前言 Rust好像长期以来不支持Windows XP系统.有不少用户发帖提议官方支持XP,基本上都被Rust官方开发人员明白的拒绝了.他们的对话大致上是以这种形式開始和结束的(当中乙方代表官方及其拥趸 ...

  4. Windows改动cmd字符集

    在中文Windows系统中,假设一个文本文件是UTF-8编码的,那么在CMD.exe命令行窗体(所谓的DOS窗体)中不能正确显示文件里的内容.在默认情况下,命令行窗体中使用的代码页是中文或者美国的,即 ...

  5. Effective JavaScript Item 40 避免继承标准类型

    本系列作为Effective JavaScript的读书笔记. ECMAScript标准库不大.可是提供了一些重要的类型如Array,Function和Date.在一些场合下.你或许会考虑继承当中的某 ...

  6. linux和unix的对照

    在之前的博客中说到,linux是一个单一内核的操作系统,但它与传统的单一内核UNIX操作系统不同. 在普通单一内核系统中,全部内核代码都是被静态编译和链接的. 而在linux中,能够动态的装入和卸载内 ...

  7. BZOJ 1578 DP

    思路:裸的完全背包 //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> ...

  8. Unix/Linux环境下多一点不如少一点

    正如很多人所知道的$PATH环境变量里存着一张目录列表,当用户要执行某一程序时,系统就会按照列表中的内容去查找该程序的位置.当程序名前不带点斜线 . / 时$PATH就会起作用. 对于普通用户和roo ...

  9. mybatis集成到spring理解

  10. 自动与因特网时间服务器同步 NTP 服务器 pool.ntp.org, 120.24.166.46 端口 123

    自动与因特网时间服务器同步   NTP 服务器 pool.ntp.org 海康提供的NTP服务器   120.24.166.46     端口  123