【问题标题】:Is using exceptions for normal control flow a practice to be discouraged or not?是否不鼓励对正常控制流使用异常?
【发布时间】:2013-08-23 09:02:16
【问题描述】:

如果函数失败是正常的,例如在数据库中找不到记录或任何其他表明可能缺少值的情况,是否建议使用异常来处理这种情况?

示例伪代码:

function retrieve(foo):
  results = db.query("SELECT * FROM bar WHERE foo="+foo)
  if not results:
    throw Exception("no results")
  return results[0]

function main:
  try:
    record = retrieve(42)
  except:
    print "no record with 42"
    .... will create the record and continue
  else:
    print "record found: "+record
    .... will use the existing record and continue

另一种解决方案可能是返回空值而不是启动此异常。 哪一个最有可能成为反模式?哪些情况下最好使用异常,哪些情况下不可以?

【问题讨论】:

    标签: coding-style scalability design-patterns anti-patterns


    【解决方案1】:

    Joshua Bloch 在《Effective Java》中总结:

    异常,顾名思义,仅用于异常情况;它们不应该用于普通的控制流

    您可以在 Google 图书上找到该书对应的 sn-p(“第 57 条:仅在特殊情况下使用例外”)。

    除了异常滥用可能导致代码难以理解的原因之外,Bloch 还有一些对当今 JVM 实现有效的原因:

    因为例外是为特殊情况而设计的,所以几乎没有 激励 JVM 实现者使它们与显式测试一样快。

    在(Hotspot)JVM 的情况下,创建异常非常昂贵(想想生成的堆栈跟踪)。

    【讨论】:

      【解决方案2】:

      来自.Net Framework Development Guidelines:

      如果可能,请勿将异常用于正常的控制流程。

      除了系统故障和具有潜在竞争条件的操作外,框架设计者应设计 API,以便用户可以编写不会引发异常的代码。例如,您可以提供一种在调用成员之前检查先决条件的方法,以便用户可以编写不会引发异常的代码。

      用来检查另一个成员的先决条件的成员通常被称为测试者,而真正做这项工作的成员被称为执行者。

      在某些情况下,Tester-Doer Pattern 可能会产生不可接受的性能开销。在这种情况下,应考虑所谓的 Try-Parse 模式(有关详细信息,请参阅异常和性能)。

      【讨论】:

        【解决方案3】:

        使用异常通常会导致更高的开销,滥用它们可能会减慢您的应用程序。在查询中找不到任何记录并没有什么异常,所以我肯定会建议返回空值。

        所以不,对正常控制流使用异常不是一个好习惯。

        【讨论】:

          猜你喜欢
          • 2015-06-14
          • 2011-12-19
          • 1970-01-01
          • 2020-04-05
          • 2015-08-24
          • 2011-11-08
          • 1970-01-01
          • 2010-11-09
          • 1970-01-01
          相关资源
          最近更新 更多