我的理解是,普遍的智慧说只使用异常才能获得真正特殊的条件(事实上,我已经多次在SO上看到过这种说法).
然而,Krzysztof Cwalina说:
关于例外的最大误解之一是它们用于"特殊条件".现实情况是它们用于传达错误条件.从框架设计的角度来看,没有"特殊条件"这样的东西.条件是否异常取决于使用的上下文,但可重用的库很少知道如何使用它们.例如,对于简单的数据输入应用程序,OutOfMemoryException可能是例外; 对于进行自己的内存管理的应用程序(例如SQL服务器)来说,这并不是那么特别.换句话说,一个人的特殊情况是另一个男人的慢性病.
然后,他接着说,例外情况应该用于:
使用错误
程序错误
系统故障
考虑到Krzysztof Cwalina是MS CLR团队的PM,我问:你如何看待他的陈述?
这听起来过于简单,但我认为在适当的地方使用异常是有意义的.在Java和Python等语言中,异常非常常见,特别是在某些情况下.异常适用于您希望通过代码路径冒出的错误类型,并强制开发人员明确捕获.在我自己的编码中,我认为在错误要么无法忽略时添加异常的正确时间,或者抛出异常而不是向函数调用返回错误值等更优雅.
我可以随意思考的一些最合适的例外场所:
NotImplementedException - 指定特定方法或函数不可用的非常合适的方式,而不是简单地返回而不做任何事情.
OutOfMemory异常 - 很难想象一种更好的方法来处理这种类型的错误,因为它代表了一个进程范围或操作系统范围的内存分配失败.当然,这对于处理至关重要!
NullPointerException - 访问null变量是一个程序员错误,而IMO这是另一个强制错误冒泡到表面的好地方
ArrayIndexException - 在像C这样的无用语言中,缓冲区溢出是灾难性的.较好的语言可能返回某种类型的空值,或者在某些实现中,甚至包围数组.在我看来,抛出异常是一种更优雅的反应.
这绝不是一个全面的清单,但希望它说明了这一点.在优雅和合乎逻辑的情况下使用例外.与编程一样,正确工作的正确工具是很好的建议.毫无意义的例外 - 无所事事,但完全忽略一个强大而优雅的工具同样是不明智的.
对于编写框架的人来说,也许这很有趣.
对于我们其他人来说,这是令人困惑的(也可能是无用的.)对于普通应用程序,必须将异常作为"特殊"情况搁置.异常会中断程序的普通顺序显示.
你应该谨慎地打破常规的从上到下顺序处理你的程序.异常处理是 - 故意 - 难以阅读.因此,为标准方案之外的事物保留例外.
示例:不要使用异常来验证用户输入.人们总是犯输入错误.这不是特例,这就是我们编写软件的原因.这就是if语句的用途.
当您的应用程序获得OutOfMemory异常时,抓住它是没有意义的.这是特殊的."顺序执行"假设超出了窗口.您的应用程序注定失败,只是崩溃并希望您的RDBMS事务在崩溃之前完成.
确实很难确定究竟是什么构成了"特殊条件",它保证在程序中使用例外.
一个对使用沟通错误原因非常有帮助的实例.正如Krzysztof Cwalina的引述所提到的:
关于例外的最大误解之一是它们用于"特殊条件".现实情况是它们用于传达错误条件.
举一个具体的例子,假设我们有一个getHeader(File f)
方法是从文件中读取一些头并返回一个FileHeader
对象.
尝试从磁盘读取数据可能会产生一些问题.也许指定的文件不存在,文件包含无法读取的数据,意外的磁盘访问错误,内存不足等.有多种失败方法意味着应该有多种方法来报告出错的地方.
如果没有使用异常,但是需要传达发生的错误类型,使用当前的方法签名,我们最好的办法就是返回一个null
.由于获得的null
信息不是很丰富,我们从该结果中获得的最佳沟通是"发生了某种错误,所以我们无法继续,抱歉." - 它不会传达错误原因.
(或者可替换地,我们可具有用于其指示FileNotFound条件等,仿真错误代码FileHeader里的对象类的常量,但真正具有恶臭用布尔型的TRUE
,FALSE
,FILE_NOT_FOUND
.)
如果我们得到了一个FileNotFound
或DeviceNotReady
异常(假设),至少我们知道错误的来源是什么,如果这是最终用户应用程序,我们可以通过解决问题的方式来处理错误.
使用异常机制提供了一种通信方式,不需要回退使用错误代码来通知不在正常执行流程内的条件.
但是,这并不意味着一切都应该由例外处理.正如S.Lott所指出的那样:
例如,不要使用异常来验证用户输入.人们总是犯错误.这就是if语句的用途.
这是一件无法强调的事情.不知道何时使用例外的危险之一是倾向于异常快乐; 使用输入验证就足够的例外.
InvalidUserInput
当处理这种情况所需要的只是通知用户期望输入的内容时,定义和抛出异常确实没有意义.
此外,应该注意的是,用户输入在某些时候预计会有错误的输入.在将来自外部世界的输入传递给程序内部之前,验证输入是一种防御性措施.
决定什么是特殊的,什么不是什么有点困难.
因为我通常使用Python编程,并且在那种语言中,异常无处不在,对我来说异常可能代表从系统错误到完全合法条件的任何事情.
例如,检查字符串是否包含整数的"pythonic"方法是尝试int(theString)并查看它是否引发异常.这是一个"特殊错误"吗?
同样,在Python中,for循环总是被认为是作用于迭代器,并且迭代器必须在完成其作业时引发'StopIteration'异常(for循环捕获该异常).这种"特殊"无论如何?