为什么在编程语言中将错误命名为“ Exception”而不是“ Error”?


45

实际上我已经思考了很长时间。我自己不是英语为母语的人,但是我仍然有多年编程经验,所以我总是问我这个问题。为什么将其命名为Exception而不是Error,因为它们是错误。

可以PageNotFoundError代替PageNotFoundException


41
并非所有例外情况都是错误。
Andrew T Finnell

15
转弯和撞车之间的区别。
世界工程师

6
您只是在谈论特定异常类的命名吗?然后注意,在某些生态系统中,它们称为XYError-例如在Python中。

6
请注意,Java确实有一个Error类,该类继承自Throwable。有关更多详细信息,请参见docs.oracle.com/javase/1.4.2/docs/api/java/lang/Error.html。您可能还希望检查“直接已知子类”类别。
luiscubal 2012年

我想说这个难题与英语无关。无论您选择精通哪种语言,这都是一种逻辑上的分类。
שינתיאאבישגנת

Answers:


59

它们根本不需要是错误。页面不存在的事实可能只是一个有趣的事实,而不是实际的错误。 我承认,它们似乎几乎总是被当作错误来使用。但是有时候,它们被用来打破循环,或者让您知道字符串不是有效的数字。它们可以用来保存和返回大量有用的数据-作为相当正常的返回的一部分。(某些语言的例外情况有点慢,在这种情况下,经常抛出它们是一个坏主意。)从理论上讲,例外情况只是意味着“不要进行正常的回报,直到发现感兴趣的人后,再调用堆栈在这。”

即使是空指针异常也可能对您没有多大意义。您调用别人的代码,然后捕获一个空指针异常,因为您知道它很容易崩溃,打印一条消息,指出是谁的错误,然后继续进行工作。


27
尽管使用异常机制作为控制流可能会造成混淆,并且我认为通常对此并不满意。
ChaosPandion 2012年

11
@ChaosPandion:取决于语言/文化。
amara 2012年

11
@DocBrown:我曾经写过一个sudoku求解器,它进行递归搜索,当它在当前尝试中未能找到解决方案并以其他值重试时回溯。找到解决方案后,它将引发包含解决方案的异常。这里失败的问题是“正常”情况,成功是“异常”情况;并且由于在求解器中有多个要调用其自身的点,因此在不使用异常的情况下,您必须编写大量样板来检查调用是从成功搜索还是从失败搜索返回。
Lie Ryan

5
@Falcon:是的,您只可以返回一个“ finished”值,这意味着每次递归时都需要做:for (...) { if (func() == finished) { return finished; } else { itfailedsocheckanother(); }}但是考虑到代码中有多个要递归func()的点,每次添加更多的递归时,无异常解决方案都会变得更加难看。就是我所说的“货物崇拜”编程,它本质上是用一种已经存在的语言模拟异常,因为邪教首领说“你不应该使用异常”。
Lie Ryan

8
@Falcon:啊...股票“看起来像Goto”参数,该参数用于表示您不应该使用循环或if语句或函数调用,因为“它们看起来都像gotos”。如果将异常与错误相关联,则返回异常成功是WTF。对我而言,以这种方式使用try-catch块就像“一个长途跋涉返回这里的承诺”一样,try-except + throw的行为与function-calls + returns非常相似,只不过它用于当您完成寻求解决方案的过程时,行程可能更长,可能涉及很深的调用堆栈。
Lie Ryan

21

异常机制并不总是用于表示错误。异常是在异常情况下抛出的,这种情况需要使用单独的代码路径来处理,包括错误。例如,用户提供不存在的文件名,或者在数字字段中输入字母而不是数字,这是需要特殊处理的特殊情况,但这不是错误。

在某些编程环境(例如Java)中,Error提供了特殊对象来报告“真实错误”,而合理的应用程序不应尝试处理这种情况。这些对象使用与传递异常相同的机制进行传递,但是它们具有不可恢复情况的信号的特殊含义。


6

我没有关于该词源的词源研究,但我可以理解,使用“错误”一词可能并非在所有情况下都是准确的;同样,正如几乎SharepointMaster所提到的,最好将错误和异常视为单独的实体。

当您使用高级编程语言时,有理由假定异常总是由错误引起的,尽管我也同意dasblinkenlight的观点,即使那样,异常也不总是由错误引起的。例如,我使用异常来协作终止线程。

我第一次看到“例外”一词是在80386汇编手册中。我记得当我看到它对我来说立即自然。称一个错误将是不正确的,因为Assembly中没有错误。存在处理器无法处理的简单条件(如果这是错误-来自程序员,用户或系统-那么,处理器对此完全不可知)。我不知道英特尔是否真正起源于该术语,但也许...


3

通常,Exception用于命名不正确但可以从中恢复的事件,就像out_of_rangeC ++中的异常一样,当访问不存在的向量或数组中的元素时会抛出该事件。显然,这样的事件是不正确的,但是它发生并不意味着整个程序崩溃。

另一方面,错误通常用来命名应该使所有程序崩溃的东西,例如堆栈溢出是事件的示例,该事件应终止程序,因为程序无法在内部处理它。换句话说:错误是主要的,而异常则相对较小。


3

我认为这与错误处理的“演变”有关。使用C / C ++(在添加异常处理之前)语言,如果函数失败,则唯一的方法就是通过返回值(例如,HRESULT在Win32中)。因此,通常您最终会捕获每个函数调用的退出代码并进行检查。这种方法使代码更加混乱。很多时候,开发人员只会避免懒惰地添加这些检查。

随着异常处理的引入,开发人员现在有两种选择可以引发错误。因此,使用“例外”一词来区分错误和“退出状态”错误。一段时间之后,异常处理已成为一种流行的传播错误的方法,因为代码更易于阅读,维护,并且可以在一个地方拥有错误处理逻辑。



1

发生错误时,系统或当前正在执行的应用程序都会通过引发包含有关错误信息的异常来报告该错误。一旦引发,异常将由应用程序或默认异常处理程序处理。

错误会引发一个详细说明该错误的异常,因此,并非所有错误都属于错误;如果这有意义,那么它就是一个例外;),例如,noneimplemetedexception应该不是一个错误,但会引发一个异常。

http://msdn.microsoft.com/zh-CN/library/system.exception.aspx


0

在iOS / Mac编程中,我们只有一种语言同时具有“异常”和“错误”。

至少在那种环境下,异常是“不可恢复的”,而错误是“可恢复的”。

例如:

  • 如果您有一个包含10个项目的数组,并且尝试在索引30处访问该项目-这将是一个例外。您在编程中犯了一个错误。
  • 如果您尝试下载URL但没有Internet连接,那是可以预期的,您应该向用户显示某种消息。

异常通常会使您的应用程序崩溃,而错误通常会返回nil并返回一个错误对象(作为按引用方法的参数返回)。您可以使用try / catch / finally块来捕获异常,但是建议不要使用此语言功能-如果可以以任何方式从异常中恢复,则根本不应该引发异常(应该返回错误对象)。


2
好吧,这与异常和错误对其他开发人员的意义完全不同!
塔里克

我猜每种语言都是不同的。Objective-C / Cocoa是活跃使用的最古老的语言之一(大约在1983年左右),因此也许有点过时了。但是,如果定义从一个社区更改为另一个社区,则一定要知道这一点。
阿比·贝克特

0

一个错误的东西,在程序的执行出了问题。通常,这是通过引发异常来解决的,但是

  • 没有什么可以迫使程序员通过引发异常来处理错误,并且
  • 没有什么可以强迫程序员仅在出现错误的情况下引发异常。

错误是一个语义概念:具有期望的程序员或用户使用它来描述他们的期望与现实之间的差异。只有一个人可以说出例程是否处于错误状态。

语法概念是一个例外:它本身就是程序中的某些东西,与任何人对该程序应该做什么的期望无关。例程会引发异常,也不会引发异常,而不管任何人的想法如何。


0

异常和错误是不同的。

例外是程序可以克服的情况,例如说您尝试打开一个文件但该文件不存在,而错误是程序无法执行任何操作的情况,例如磁盘故障或RAM故障。


0

引发和处理异常是控制流功能,并且异常的名称应遵循预期的用法。代码和API的设计者应找到良好且一致的命名方案。

因此,您的问题的答案是:它取决于上下文和视角。


0

异常是错误的概括。在第一编程语言包括异常机制是Lisp语言在70年代初期。加布里埃尔(Gabriel)和斯蒂尔(Steele)《语言进化模式》中有一个很好的总结。异常(尚未称为异常)是由于发生错误时需要指定程序的行为而引起的。一种可能性是暂停程序,但这并不总是有帮助的。传统上,Lisp实现有一种针对错误进入调试器的方法,但是有时程序员希望在其程序中包括错误处理。因此,1960年代Lisp的实现方式有一种说法:“这样做,如果发生错误,则改为这样做”。错误最初来自原始函数,但是程序员发现故意触发错误以便跳过程序的某些部分并跳转到错误处理程序很方便。

1972年,Lisp中异常处理的现代形式出现在MacLisp中:throwcatch。该软件保存组列出了早期Lisp的实现,其中包括了大量的材料由大卫月亮MACLISP参考手册修订0。原始语言catchthrow记录在§5.3p.43中。

catch是用于执行结构化非本地出口的LISP函数。(catch x)评估x并返回其值,除了在评估期间x (throw y)应评估时,catch立即返回y而无需进一步评估x

catch也可以与未经评估的econd参数一起使用,该参数用作区分嵌套捕获的标记。(...)

throwcatch结构化的非本地退出机制一起使用。

(throw x)评估x并将值返回最新的catch

(throw x <tag>)x返回的值返回到最近catch标记为<tag>或未标记的值。

重点是非本地控制流。这是goto的一种形式(仅向上的goto),也称为jump。隐喻是程序的一部分抛出该值以返回到异常处理程序,并且异常处理程序捕获该值并返回它。

如今,大多数编程语言都将标记和值打包在异常对象中,并将捕获机制与处理机制结合在一起。

异常不一定是错误。它们是从代码块和周围的块中退出的一种方式,转义直到到达异常的处理程序。在直觉上,这种事情是否被认为是“错误”是主观的。

一些语言在术语“错误”和“例外”之间进行区分。例如,某些Lisp方言既throw要引发异常(用户的控制流,即要以不指示任何“错误”的方式执行非本地退出),也signal必须引发错误(这表明出现“错误”,并可能触发调试事件)。


-1

您会发现它在不同的编程语言实现中有不同的解释。正如dasblinkenlight所说,这是在错误和异常之间进行分界的一种Java观点。在许多编程语言中,异常是可以处理或允许冒泡传递给最高代码模块的违规。错误通常是语言的运行时容器处理的情况(很多情况下只是停止执行)。


-1

错误永远是错误。异常是当前上下文中的错误。也就是说,异常是上下文相关的。例外的一个示例是将ascii“ a”添加到整数“ 1”。错误可能类似于使用未定义的运算符,例如“ +!”。在大多数语言中。

如果确实要这样做,则可以使用某些语言来定义摆脱情况的方式。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.