关于使用Exception的一点心得

时间:2023-03-09 05:50:46
关于使用Exception的一点心得

毫无疑问,Exception有很多优点。查看任何一本面向对象的书籍,都会提到异常相对于返回值标记状态的不足以及避免错误导致程序崩溃的问题。看起来是很好的,用起来也是很好的。可是这么多年过去了,异常用的并不是很好,甚至有点不知所谓。最近用异常有点感觉,所以拿出来分享一下。

首先说之前异常用起来没有感觉的原因:

  1. 异常能发现问题,却并不能很好的解决问题。比如,某个方式封装了打开数据连接的操作,内部调用一个打开数据库的库函数,此刻函数抛出了连接异常。异常可以方便调试,可是即使捕获到重试,依然不能解决问题。如果想在此函数捕获异常后重新尝试打开,还得限制重试次数,避免死循环。在重试或者处理过之后,还得反馈给外部进行处理。
  2. 函数出现异常了,然后呢?当我们对别人的库进行一下封装的时候,为了不暴露封装库,甚至直接将异常捕获,用函数返回值替代了异常。既然体会不到异常的好处,又多写了代码。重新抛出异常好像也是一件浪费时间的事情。
  3. 一些不好示范。不习惯异常的可能更多的是C/C++等程序员,总是喜欢0,-1,1。好一点的会将0,-1转换为false,1转换为true。用起来也没有什么不好,可是不知道false的具体含义。虽然在Debug时,会有栈追踪,却始终是放弃了异常的好处。很多年前见过我师兄简单封装的Apache的一个java SQL 访问的包(DBUtil),就是这么干的。甚至,连事务都被其干掉了。
  4. 不要吞食异常。在使用一些硬件公司(即使是我们选用的知名的硬件公司)提供的.Net SDK基本上都来自对C/C++的最基本封装——可是说只是转换了签名。每当我使用这样的SDK,真让人崩溃。风格自然不用说,还喜欢吞食异常。吞食异常的后果就是,你永远无法知道SDK是否出错,或者到底哪里出错。硬件公司的.Net SDK风格一方面可能来自于其对C/C++的简单封装,根本无异常;另一方面也可能由于于他们没有定义好或者描述好错误。以下是吞食异常的一个示例:
    //example code
    try
    {
    dosomething(); //will throw exception.
    }
    catch(Excetpion ex)
    {
    //log.... or other things
    // or do nothing
    }

我一直在想怎么用好异常,最近用起来感觉比较顺手,大概有这么几点心得:

  • 如果这个类方法对其具体实现的异常(比如调用了其他库抛出的异常)不敢兴趣,那么就不用理会,当作什么都不知道。除非需要捕获异常进行记录,并封装,抛出自己定义的异常,才捕获它们。
  • 类方法只是执行实体,不是控制实体,异常抛出后,如何处理应该由控制器来进行逻辑处理。
  • 对于自己实现的类方法,应该主动的抛出异常,让客户知道发生了什么错误。最简单的就是 throw new Exception("what is wrong....")
  • 在功能性方法中处理异常没有任何意义,还会其他客户端带来困惑。比如打开串口异常时存在重试逻辑,那么该方法可能会卡住。该方法的客户端需要知晓该方法的处理逻辑。

如果你的方法对异常不感兴趣,或者你无法处理它,就不要关注它。如果你需要抛出新异常,大胆的throw就好,只需要将exception说明加入到注释即可。将异常交给其使用者处理,是非常好的一件事情。

/// <summary>
/// 函数说明
/// </summary>
/// <param name="content"></param>
/// <exception cref="System.Exception">将抛出异常..</exception>
public void SayHello(param content[])

参考:

[1]《译<异常最佳实践>》, http://www.cnblogs.com/jjseen/p/5922852.html

[2].Net最佳实践, (美)Stephen Ritchine 著, p75-80, 机械工业出版社