fbpx
维基百科

异常处理

计算计算机编程领域中,例外處理(exception handling,也意译为异常处理,需注意“异常”一般对应英文abnormality[1]),是对出现的例外的响应处理,在程序执行英语Execution (computing)期间,异常或例外情况需要特殊处理。一般而言,例外打断正常的执行流程并执行预先登记的“例外处理器”;具体如何去做依赖于它是硬件还是软件例外,还有软件例外是如何实现的。

例外是由计算机系统的不同层级来定义的,典型的层级有CPU定义的中断操作系统(OS)定义的信号编程语言定义的例外。每个层级都要求不同例外处理方式,但是它们可以是关联的,比如说CPU中断可能被转变成OS信号。一些例外特别是硬件例外,可以被优雅地处理使得程序执行能在它被中断的地方恢复。

硬體的例外处理 编辑

硬體的异常处理机制由CPU完成。这种机制支持错误检测,在发生错误后会将程序流跳转到专门的错误处理例程中。发生异常前的状态存储在栈上。[2]

操作系统的例外处理 编辑

针对程序中可能发生的例外,操作系统可能通过IPC来提供对应的处理设施。进程执行过程中发生的中断通常由操作提供的「中断服务子程序」处理,操作系统可以藉此向该进程发送信号。进程可以通过注册信号处理器的方式自行处理信号,也可以让操作系统执行預設行为(比如终止该程序)。

从进程的视角,硬體中断相当于可恢复异常,虽然中断一般与程序流本身无关。

编程语言的例外处理 编辑

编程语言领域,通常例外(英語:exception)这一术语所描述的是一种資料结构,该資料结构可以存储例外的相关訊息。例外处理的常见的一种机制是移交控制权。引发(raise)异常,也叫作抛出(throw)异常,通过该方式达到移交控制权的效果。例外抛出后,控制权会被移交至某处的(catch),并执行处理。

编程语言对例外有着截然不同的定义,而现代语言大致上可分两类:[3]

  • 用作于控制流程的例外,如:Ada、Java、Modula-3、ML、OCaml、Python、Ruby 。
  • 用作于处理异常、无法预测、错误性的情况。如:C++[4]、C#、Common Lisp、Eiffel、Modula-2 。

子程序作者的角度看,如果要表示当前子程序无法正常执行,抛出例外是很好的选择。无法正常执行的原因可以是输入参数无效(比如值在函数的定义域之外),也可以是无法获得所需的资源(比如文件不存在、硬碟出错、内存不足)等等。在不支持例外的系统中,子程序需要通过返回特殊的错误码英语Error code實作类似的功能。然而回傳错误码可能导致不完全预测问题英语Semipredicate problem,子程序的使用方需要编写额外的代码,才能将普通的回傳值与错误码相区别。

Kiniry强调:“语言设计仅仅部分地影响了对例外的使用,从而影响编程者处理系统执行期间部分或所有失败的方式。其他主要的影响还有在核心库、技术书籍、杂志文章、在线研讨论坛和特定组织的代码标准中的使用示例”。[5]

历史 编辑

在1960和1970年代,Lisp语言发展出軟體例外。最初版本是在1962年Lisp 1.5的时候,这时候异常通过ERRSET关键词进行捕捉,并在出错时候,通过NIL进行回傳,而不是以前的终止程序或者进行调试器。[6]1960年代后半,Maclisp语言通过ERR关键词引入“引发”(Raise)错误机制。[6]Lisp的这种创新不仅仅被应用于抛出错误,还被应用于“非局部控制流”。在在1972年6月,Maclisp语言通过CATCHTHROW两个新的关键词来实现非局部控制流,并保留ERRSETERR专门做错误处理。在1970中后,NIL英语NIL (programming language)(“新实现的LISP”)衍生出清除操作UNWIND-PROTECT,对应着现今常见的finally[7]该操作也被Common Lisp使用了。与之同时代,Scheme也诞生了dynamic-wind,用于处理闭包中的异常。Goodenough (1975a)和Goodenough (1975b)是介绍结构化的异常处理的开创性文章。[8] 1980年后,异常处理被廣泛利用于许多编程语言。

PL/I语言使用的是动态作用域例外,然而稍微现代的编程语言多用词法作用域的例外。PL/I语言的例外处理包含事件(不是错误)、注意(Attention)、EOF、列举了的变量的修改(Modification of listed variables)。虽然现在的一些编程语言支持不含错误信息的例外,但是他们并不常见。

一开始,軟體的例外处理是包含可恢复的例外,它具有恢复语义,就像大部分的硬體例外一样,以及不恢复的例外,它具有终止语义。但是,在1960和1970时代,在实践中得出恢复语义是十分低效的(C++标准相关的讨论可见[9]),因此恢复语义就很少再出现了,通常只能在类似Common Lisp和Dylan这种语言中见到。

批评 编辑

1980年Tony Hoare在评论Ada语言时,将异常处理提及为危险特征。[10]

对于软件而言,异常处理经常无法正确的处理,尤其是当这里有多种来自不同源代码的异常时。在对五百万行Java代码进行数据流分析时,我们发现了超过1300个异常处理。[11]这是1999-2004年的前沿报告以及他们的结论,Weimer和Necula写到,异常是一个十分严峻的问题,他们会创造隐藏的控制流途径,这种途径是编程人员很难去推理的。

Go语言的初始版本并没有异常处理,而因此被有的开发者认为控制流十分冗余。[12]后来,追加了类似的异常处理的语法panic/recover机制,但是Go语言的作者建立这仅仅在整个程序不可恢复的错误时候使用它。[13][14][15][16]

异常,作为一个非结构化的流程,它会增加资源泄露的可能性(如:从锁住的代码中逃脱,在打开文件时候逃脱掉),也有可能导致状态不一致。因此,出现了集中异常处理的资源管理技术,最常见的结合dispose pattern和解除保护(unwind protection)一起使用(如finally语句),会在这段代码的控制权结束时自动释放资源。

编程语言相关支持 编辑

许多常见的程序设计语言支持异常处理,包括:

多数语言的异常机制的语法是类似的:用throwraise抛出一个异常对象(Java或C++等)或一个特殊可扩展的枚举类型的值(如Ada语言);异常处理代码的作用范围用标记子句(trybegin开始的语言作用域)标示其起始,以第一个异常处理子句(catch, except, rescue等)标示其结束;可连续出现若干个异常处理子句,每个处理特定类型的异常。某些语言允许else子句,用于无例外出现的情况。更多见的是finally, ensure子句,无论是否出现异常它都将执行,用于释放异常处理所需的一些资源。

C语言没有try-catch异常处理,而是使用返回码英语Error code用于错误检查;setjmplongjmp标准库函数可以被用来通过宏实现try-catch处理[17]。一般在异常处理代码的搜索过程中会逐级完成栈卷回(stack unwinding);但Common Lisp中进行异常处理的条件系统,不采取栈卷回,因此允许异常处理完后在抛出异常的代码处原地恢复执行。

C++ 编辑

C++异常处理资源获取即初始化(RAII)的基础。异常事件在C++中表示为“异常对象”(exception object)。异常事件发生时,由操作系统为程序设置当前异常对象,然后执行程序的当前异常处理代码块,在包含了异常出现点的最内层的try块,依次匹配同级的catch语句。如果匹配catch语句成功,则在该catch块内处理异常;然后执行当前try...catch...块之后的代码。如果在当前的try...catch...块没有能匹配该异常对象的catch语句,则由更外一层的try...catch...块处理该异常;如果当前函数内的所有try...catch...块都不能匹配该异常,则递归回退到调用栈的上一层函数去处理该异常。如果一直回退到主函数main()都不能处理该异常,则调用系统函数terminate()终止程序。

Python 编辑

Python中只存在语法错误和例外。语法错误是在运行之前发生的。而例外是在运行时发生的错误,除非进行捕捉处理,否则它将无条件停止程序。可以书写代码来处理选定的例外。[18]

Python语言中对例外处理机制的采用是非常普遍深入的,这种编码风格被称为EAFP(请求原谅比得到许可更容易)[19],它假定有效的键或特性存在,并在这个假定证明失败时捕获例外。Python社区认为这种风格是清晰而快速的,它的特征是会出现很多tryexcept语句。这种技术对立于常见于很多其他语言比如C语言中的LBYL(看好再跳)风格。

Java 编辑

Java中异常是异常事件(exceptional event)的缩写。异常是一个事件,它发生在程序运行时并会打乱程序指示的正常流程。当方法出现了错误时,方法会创建一个对象并将它交给运行时系统,所创建的对象叫“异常对象”,该对象包含了错误的信息(描述了出错时的程序的类型和状态)。创建错误对象和转交给运行时系统的过程,叫抛出异常。[20]

class RuntimeExceptionclass Error均是不检查的异常(Unchecked Exceptions)。[21]错误不等于错误类(class Error),错误类代表着不应该被捕捉的严重的问题。[22]class RuntimeException 意味着程序出现问题了。[21]

Go 编辑

Go语言提倡的是错误处理(error handling)。Go语言设计者系统希望使用者在错误出时,显式地检查错误。[23] Go虽然不提供与Java语言的try..catch同等的功能语句,但是取而代之,提供了轻型的异常处理机制panic...recover[24]

.NET语言 编辑

大多数.NET程序设计语言,内建的异常机制都是沿着函数调用栈的函数调用逆向搜索,直到遇到异常处理代码为止。而 Visual Basic(尤其是在其早于 .net 的版本,例如 6.0 中)走得更远:on error 语句可轻易指定发生异常后是重试(resume)还是跳过(resume next)还是执行程序员定义的错误处理程序(goto ***)。

错误处理 编辑

错误处理(error handling)是通过处理函数的返回值的形式从而处理错误的一种编程方式。在Go等返回值可为复数的语言中,可通过将其中一个值设为错误值,从而达到错误处理的效果。

f, err := os.Open("filename.ext") if err != nil {  log.Fatal(err) } // do something with the open *File f 

在仅仅支持返回状态码的语言里,可通过处理错误码,达到错误处理的效果。shell语言可通过$?获得函数执行的退出码,从而判断是否出错。

在其他语言中,可以通过判断结果的某一个特征,从而达到错误处理部分的效果,但不意味着这些语言自身支持错误处理。如,Java等面向对象的语言往往会通过null值判断是否执行失败,但有时候也会通过异常处理判断是否执行失败。

技术问题 编辑

未捕捉异常 编辑

如果一个异常抛出后,没有被捕捉,那么未捕捉异常(uncaught exception)将会在运行时被处理。进行该处理的例程叫“未捕捉异常处理器”(uncaught exception handler[25][26]。大部分的处理是终止程序并将错误信息打印至控制台,该信息通常包含调试用的信息,如:异常的描述信息、栈追踪[27][28][29]通常处于最高级(应用级别)的处理器,即便捕捉到异常也会避免终止自身(如:线程出现异常,主线程也不会终止)。[30][31]

值得了解的是,在即便未捕捉异常导致了程序异常中断(如:异常没被捕捉、滚动未完成、没释放资源),程序仍旧能正常地顺序性地关闭。只要确保运行时系统能正常地运行,因为运行时系统控制着整个程序的执行。

作为默认的未捕捉异常处理器是可以被替换的,不管是全局还是单线程的,新的未捕捉异常处理器可以尝试做这些事情:未捕捉异常导致关闭了的线程,使之重启;提供另一种方式记录日志;让用户报告未捕捉异常等等。在Java中,单一线程可以使用Thread.setUncaughtExceptionHandler[32],全局可以用Thread.setDefaultUncaughtExceptionHandler[33];在python中,可通过修改sys.excepthook[34]

异常的静态检查 编辑

检查性异常 编辑

Java的设计者设计了[35] 检查性异常(Checked exceptions)[36]。当方法引发“检查性异常”时,“检查性异常”将成为方法符号的一部分。例如:如果方法抛出了IOException ,我们必须显式地使用方法符号(在Java中是try...catch),如果不这样做的话将会导致编译时错误。

异常安全 编辑

一段代码是“异常安全的”,如果这段代码运行时的失败不会产生有害后果,如内存泄露、存储数据混淆、或无效的输出。异常安全可分成不同层次:

  1. “失败透明”,也称作“不抛出保证”:代码的运行保证能成功并满足所有的约束条件,即使存在异常情况。如果出现了异常,将不会对外进一步抛出该异常。(异常安全的最好的层次)
  2. “提交或卷回的语义”,或称作“强异常安全”或“无变化保证”:运行可以是失败,但失败的运行保证不会有负效应,因此所有涉及的数据都保持代码运行前的初始值。[37]
  3. “基本异常安全”:失败运行的已执行的操作可能引起了副作用,但会保证状态不变。所有存储数据保持有效值,即使这些数据与异常发生前的值有所不同。
  4. “最小异常安全”,也称作“无泄漏保证”:失败运行的已执行的操作可能在存储数据中保存了无效的值,但不会引起崩溃,资源不会泄漏。
  5. “没有异常安全”:没有保证(最差的异常安全层次)。

例如,考虑一个smart vector类型,如C++的 std::vector或Java的 ArrayList。当一个数据项x插入vector v,必须实际增加x的值到vector的内部对象列表中并且修改vector的计数域以正确表示v中保存了多少数据项;此时如果已有的存储空间不够大,就需要分配新的内存。内存分配可能会失败并抛出异常。因此,vector数据类型如果是“失败透明”保证将会非常困难甚至不可能实现。但vector类型提供“强异常安全”保证却是相当容易的;在这种情况下,x插入v或者成功,或者v保持不变。如果vector类型仅提供“基本异常安全”保证,如果数据插入失败,v可能包含也可能不包含x的值,但至少v的内部表示是一致的。但如果vector数据类型是“最小异常安全”保证,v可能会是无效的,例如v的计数域被增加了,但x并未实际插入,使得内部状态不一致。对于“异常不安全”的实现,程序可能会崩溃,例如写入数据到无效的内存。

通常至少需要基本异常安全。失败透明是难于实现的,特别是在编写库函数时,因为对应用程序的复杂知识缺少获知。

引用 编辑

  1. ^ . dictionary.cambridge.org. [2020-02-04]. (原始内容存档于2021-04-14) (中文(简体)). 
  2. ^ Hardware Exceptions Detection. TEXAS INSTRUMENTS. 2011-11-24 [2012-10-05]. (原始内容存档于2013-11-10) (英语). 
  3. ^ Kiniry, J. R. Exceptions in Java and Eiffel: Two Extremes in Exception Design and Application. Advanced Topics in Exception Handling Techniques. Lecture Notes in Computer Science 4119. 2006: 288–300. ISBN 978-3-540-37443-5. doi:10.1007/11818502_16. 
  4. ^ Stroustrup: C++ Style and Technique FAQ. www.stroustrup.com. [5 May 2018]. (原始内容于2 February 2018). 
  5. ^ Kiniry, J. R. Exceptions in Java and Eiffel: Two Extremes in Exception Design and Application. Advanced Topics in Exception Handling Techniques. Lecture Notes in Computer Science 4119. 2006: 288–300. ISBN 978-3-540-37443-5. doi:10.1007/11818502_16. 
  6. ^ 6.0 6.1 Gabriel & Steele 2008,第3頁.
  7. ^ White 1979,第194頁.
  8. ^ Stroustrup 1994,第392頁.
  9. ^ Stroustrup 1994,16.6 Exception Handling: Resumption vs. Termination, pp. 390–393.
  10. ^ C.A.R. Hoare. The Emperor's Old Clothes. 1980. I have been giving the best of my advice to this project since 1975. At first I was extremely hopeful. The original objectives of the language, included reliability, readability of programs, formality of language definition, and even simplicity. Gradually these objectives have been sacrificed in favor of power, supposedly achieved by a plethora of features and notational conventions, many of them unnecessary and some of them, like exception handling, even dangerous. 
  11. ^ Weimer, W; Necula, G.C. Exceptional Situations and Program Reliability (PDF) 30 (2). 2008. (原始内容 (PDF)于2015-09-23).  |journal=被忽略 (帮助)
  12. ^ Frequently Asked Questions. [2017-04-27]. (原始内容于2017-05-03). We believe that coupling exceptions to a control structure, as in the try-catch-finally idiom, results in convoluted code. It also tends to encourage programmers to label too many ordinary errors, such as failing to open a file, as exceptional. 
  13. ^ Panic And Recover 互联网档案馆的,存档日期2013-10-24., Go wiki
  14. ^ Weekly Snapshot History. golang.org. (原始内容于2017-04-03). 
  15. ^ . golang-nuts. 25 March 2010 [25 March 2010]. (原始内容存档于2013-03-06). 
  16. ^ Effective Go. golang.org. (原始内容于2015-01-06). 
  17. ^ Roberts, Eric S. Implementing Exceptions in C (PDF). DEC Systems Research Center. 21 March 1989 [4 January 2022]. SRC-RR-40. 
  18. ^ . docs.python.org. [2020-02-04]. (原始内容存档于2022-06-08). 
  19. ^ Python documentation — Glossary — EAFP. 
  20. ^ . docs.oracle.com. [2020-02-04]. (原始内容存档于2022-06-09). 
  21. ^ 21.0 21.1 . docs.oracle.com. [2020-02-04]. (原始内容存档于2022-06-07). 
  22. ^ . docs.oracle.com. [2020-02-04]. (原始内容存档于2021-10-24). 
  23. ^ . blog.golang.org. [2020-02-04]. (原始内容存档于2021-07-12). 
  24. ^ Google 网上论坛. groups.google.com. [2020-02-04]. (原始内容存档于2011-01-22). 
  25. ^ Mac Developer Library, "Uncaught Exceptions 互联网档案馆的,存档日期2016-03-04."
  26. ^ MSDN, AppDomain.UnhandledException Event 互联网档案馆的,存档日期2016-03-04.
  27. ^ Mac Developer Library, "Uncaught Exceptions 互联网档案馆的,存档日期2016-03-04."
  28. ^ The Python Tutorial, "8. Errors and Exceptions 互联网档案馆的,存档日期2015-09-01."
  29. ^ Java Practices -> Provide an uncaught exception handler. www.javapractices.com. [5 May 2018]. (原始内容于9 September 2016). 
  30. ^ Mac Developer Library, "Uncaught Exceptions 互联网档案馆的,存档日期2016-03-04."
  31. ^ . pymotw.com. [2020-02-03]. (原始内容存档于2021-05-16). 
  32. ^ Thread.setUncaughtExceptionHandler
  33. ^ Thread.setDefaultUncaughtExceptionHandler
  34. ^ sys.excepthook
  35. ^ Google Answers: The origin of checked exceptions. [2011-12-15]. (原始内容存档于2011-08-06). 
  36. ^ Java Language Specification, chapter 11.2. http://java.sun.com/docs/books/jls/third_edition/html/exceptions.html#11.2 互联网档案馆的,存档日期2006-12-08.
  37. ^ 存档副本. [2011-08-13]. (原始内容于2009-02-03). 

参考文献 编辑

  • Black, Andrew P. Exception handling: The case against (PDF) (学位论文). University of Oxford. January 1982. CiteSeerX 10.1.1.94.5554 . OCLC 123311492. 
  • Gabriel, Richard P.; Steele, Guy L. A Pattern of Language Evolution (PDF). LISP50: Celebrating the 50th Anniversary of Lisp: 1–10. 2008. ISBN 978-1-60558-383-9. doi:10.1145/1529966.1529967. 
  • Goodenough, John B. Structured exception handling. Proceedings of the 2nd ACM SIGACT-SIGPLAN symposium on Principles of programming languages - POPL '75: 204–224. 1975a. doi:10.1145/512976.512997. 
  • Goodenough, John B. Exception handling: Issues and a proposed notation (PDF). Communications of the ACM. 1975, 18 (12): 683–696. CiteSeerX 10.1.1.122.7791 . S2CID 12935051. doi:10.1145/361227.361230. 
  • Levin, Roy. Program Structures for Exceptional Condition Handling (PDF) (学位论文). Carnegie-Mellon University. June 1977. Template:DTIC. (原始内容 (PDF)于December 22, 2021). 
  • Stroustrup, Bjarne. The design and evolution of C++ 1st. Reading, Mass.: Addison-Wesley. 1994. ISBN 0-201-54330-3. 
  • White, Jon L. NIL - A Perspective (PDF). Proceedings of the 1979 Macsyma User's Conference. May 1979. 
  • Keeton, Brian; Cavaness, Chuck; Friesen, Geoff. Special Edition Using Java 2 Standard Edition. Que Publishing. 2001. ISBN 978-0-7897-2468-7 (英语). 

外部链接 编辑

  • by Matt Pietrek - Microsoft Systems Journal (1997)
  • Article "C++ Exception Handling" by Christophe de Dinechin
  • Article "Exceptional practices" by Brian Goetz
  • Article "Object Oriented Exception Handling in Perl" by Arun Udaya Shankar
  • Article "Programming with Exceptions in C++" by Kyle Loudon
  • Article "Unchecked Exceptions - The Controversy"
  • Conference slides Floating-Point Exception-Handling policies (pdf p. 46) by William Kahan
  • Descriptions from Portland Pattern Repository


异常处理, 在计算和计算机编程领域中, 例外處理, exception, handling, 也意译为, 需注意, 异常, 一般对应英文abnormality, 是对出现的例外的响应处理, 在程序执行, 英语, execution, computing, 期间, 异常或例外情况需要特殊处理, 一般而言, 例外打断正常的执行流程并执行预先登记的, 例外处理器, 具体如何去做依赖于它是硬件还是软件例外, 还有软件例外是如何实现的, 例外是由计算机系统的不同层级来定义的, 典型的层级有cpu定义的中断, 操作系统, 定义. 在计算和计算机编程领域中 例外處理 exception handling 也意译为异常处理 需注意 异常 一般对应英文abnormality 1 是对出现的例外的响应处理 在程序执行 英语 Execution computing 期间 异常或例外情况需要特殊处理 一般而言 例外打断正常的执行流程并执行预先登记的 例外处理器 具体如何去做依赖于它是硬件还是软件例外 还有软件例外是如何实现的 例外是由计算机系统的不同层级来定义的 典型的层级有CPU定义的中断 操作系统 OS 定义的信号和编程语言定义的例外 每个层级都要求不同例外处理方式 但是它们可以是关联的 比如说CPU中断可能被转变成OS信号 一些例外特别是硬件例外 可以被优雅地处理使得程序执行能在它被中断的地方恢复 目录 1 硬體的例外处理 2 操作系统的例外处理 3 编程语言的例外处理 3 1 历史 3 2 批评 4 编程语言相关支持 4 1 C 4 2 Python 4 3 Java 4 4 Go 4 5 NET语言 5 错误处理 6 技术问题 6 1 未捕捉异常 6 2 异常的静态检查 6 2 1 检查性异常 6 3 异常安全 7 引用 8 参考文献 9 外部链接硬體的例外处理 编辑主条目 中断 硬體的异常处理机制由CPU完成 这种机制支持错误检测 在发生错误后会将程序流跳转到专门的错误处理例程中 发生异常前的状态存储在栈上 2 操作系统的例外处理 编辑主条目 Unix信号 针对程序中可能发生的例外 操作系统可能通过IPC来提供对应的处理设施 进程执行过程中发生的中断通常由操作提供的 中断服务子程序 处理 操作系统可以藉此向该进程发送信号 进程可以通过注册信号处理器的方式自行处理信号 也可以让操作系统执行預設行为 比如终止该程序 从进程的视角 硬體中断相当于可恢复异常 虽然中断一般与程序流本身无关 编程语言的例外处理 编辑主条目 例外处理 编程 英语 Exception handling programming 在编程语言领域 通常例外 英語 exception 这一术语所描述的是一种資料结构 该資料结构可以存储例外的相关訊息 例外处理的常见的一种机制是移交控制权 引发 raise 异常 也叫作抛出 throw 异常 通过该方式达到移交控制权的效果 例外抛出后 控制权会被移交至某处的接 catch 并执行处理 编程语言对例外有着截然不同的定义 而现代语言大致上可分两类 3 用作于控制流程的例外 如 Ada Java Modula 3 ML OCaml Python Ruby 用作于处理异常 无法预测 错误性的情况 如 C 4 C Common Lisp Eiffel Modula 2 从子程序作者的角度看 如果要表示当前子程序无法正常执行 抛出例外是很好的选择 无法正常执行的原因可以是输入参数无效 比如值在函数的定义域之外 也可以是无法获得所需的资源 比如文件不存在 硬碟出错 内存不足 等等 在不支持例外的系统中 子程序需要通过返回特殊的错误码 英语 Error code 實作类似的功能 然而回傳错误码可能导致不完全预测问题 英语 Semipredicate problem 子程序的使用方需要编写额外的代码 才能将普通的回傳值与错误码相区别 Kiniry强调 语言设计仅仅部分地影响了对例外的使用 从而影响编程者处理系统执行期间部分或所有失败的方式 其他主要的影响还有在核心库 技术书籍 杂志文章 在线研讨论坛和特定组织的代码标准中的使用示例 5 历史 编辑 在1960和1970年代 Lisp语言发展出軟體例外 最初版本是在1962年Lisp 1 5的时候 这时候异常通过ERRSET关键词进行捕捉 并在出错时候 通过NIL进行回傳 而不是以前的终止程序或者进行调试器 6 1960年代后半 Maclisp语言通过ERR关键词引入 引发 Raise 错误机制 6 Lisp的这种创新不仅仅被应用于抛出错误 还被应用于 非局部控制流 在在1972年6月 Maclisp语言通过CATCH和THROW两个新的关键词来实现非局部控制流 并保留ERRSET和ERR专门做错误处理 在1970中后 NIL 英语 NIL programming language 新实现的LISP 衍生出清除操作UNWIND PROTECT 对应着现今常见的finally 7 该操作也被Common Lisp使用了 与之同时代 Scheme也诞生了dynamic wind 用于处理闭包中的异常 Goodenough 1975a 和Goodenough 1975b 是介绍结构化的异常处理的开创性文章 8 1980年后 异常处理被廣泛利用于许多编程语言 PL I语言使用的是动态作用域例外 然而稍微现代的编程语言多用词法作用域的例外 PL I语言的例外处理包含事件 不是错误 注意 Attention EOF 列举了的变量的修改 Modification of listed variables 虽然现在的一些编程语言支持不含错误信息的例外 但是他们并不常见 一开始 軟體的例外处理是包含可恢复的例外 它具有恢复语义 就像大部分的硬體例外一样 以及不恢复的例外 它具有终止语义 但是 在1960和1970时代 在实践中得出恢复语义是十分低效的 C 标准相关的讨论可见 9 因此恢复语义就很少再出现了 通常只能在类似Common Lisp和Dylan这种语言中见到 批评 编辑 1980年Tony Hoare在评论Ada语言时 将异常处理提及为危险特征 10 对于软件而言 异常处理经常无法正确的处理 尤其是当这里有多种来自不同源代码的异常时 在对五百万行Java代码进行数据流分析时 我们发现了超过1300个异常处理 11 这是1999 2004年的前沿报告以及他们的结论 Weimer和Necula写到 异常是一个十分严峻的问题 他们会创造隐藏的控制流途径 这种途径是编程人员很难去推理的 Go语言的初始版本并没有异常处理 而因此被有的开发者认为控制流十分冗余 12 后来 追加了类似的异常处理的语法 span class nx panic span span class nx recover span 机制 但是Go语言的作者建立这仅仅在整个程序不可恢复的错误时候使用它 13 14 15 16 异常 作为一个非结构化的流程 它会增加资源泄露的可能性 如 从锁住的代码中逃脱 在打开文件时候逃脱掉 也有可能导致状态不一致 因此 出现了集中异常处理的资源管理技术 最常见的结合dispose pattern和解除保护 unwind protection 一起使用 如finally语句 会在这段代码的控制权结束时自动释放资源 编程语言相关支持 编辑主条目 例外处理语法 英语 Exception handling syntax 许多常见的程序设计语言支持异常处理 包括 Actionscript Ada BlitzMax C C Common Lisp D ECMAScript Eiffel Java ML Modula 2 Modula 3 Object Pascal Objective C OCaml PHP 版本5 PL I Prolog Python REALbasic Ruby Visual Prolog Scheme 大多数 NET语言 多数语言的异常机制的语法是类似的 用throw或raise抛出一个异常对象 Java或C 等 或一个特殊可扩展的枚举类型的值 如Ada语言 异常处理代码的作用范围用标记子句 try或begin开始的语言作用域 标示其起始 以第一个异常处理子句 catch except rescue等 标示其结束 可连续出现若干个异常处理子句 每个处理特定类型的异常 某些语言允许else子句 用于无例外出现的情况 更多见的是finally ensure子句 无论是否出现异常它都将执行 用于释放异常处理所需的一些资源 C语言没有try catch异常处理 而是使用返回码 英语 Error code 用于错误检查 setjmp与longjmp标准库函数可以被用来通过宏实现try catch处理 17 一般在异常处理代码的搜索过程中会逐级完成栈卷回 stack unwinding 但Common Lisp中进行异常处理的条件系统 不采取栈卷回 因此允许异常处理完后在抛出异常的代码处原地恢复执行 C 编辑 C 异常处理是资源获取即初始化 RAII 的基础 异常事件在C 中表示为 异常对象 exception object 异常事件发生时 由操作系统为程序设置当前异常对象 然后执行程序的当前异常处理代码块 在包含了异常出现点的最内层的try块 依次匹配同级的catch语句 如果匹配catch语句成功 则在该catch块内处理异常 然后执行当前try catch 块之后的代码 如果在当前的try catch 块没有能匹配该异常对象的catch语句 则由更外一层的try catch 块处理该异常 如果当前函数内的所有try catch 块都不能匹配该异常 则递归回退到调用栈的上一层函数去处理该异常 如果一直回退到主函数main 都不能处理该异常 则调用系统函数terminate 终止程序 Python 编辑 在Python中只存在语法错误和例外 语法错误是在运行之前发生的 而例外是在运行时发生的错误 除非进行捕捉处理 否则它将无条件停止程序 可以书写代码来处理选定的例外 18 Python语言中对例外处理机制的采用是非常普遍深入的 这种编码风格被称为EAFP 请求原谅比得到许可更容易 19 它假定有效的键或特性存在 并在这个假定证明失败时捕获例外 Python社区认为这种风格是清晰而快速的 它的特征是会出现很多try和except语句 这种技术对立于常见于很多其他语言比如C语言中的LBYL 看好再跳 风格 Java 编辑 在Java中异常是异常事件 exceptional event 的缩写 异常是一个事件 它发生在程序运行时并会打乱程序指示的正常流程 当方法出现了错误时 方法会创建一个对象并将它交给运行时系统 所创建的对象叫 异常对象 该对象包含了错误的信息 描述了出错时的程序的类型和状态 创建错误对象和转交给运行时系统的过程 叫抛出异常 20 class RuntimeException 和class Error均是不检查的异常 Unchecked Exceptions 21 错误不等于错误类 class Error 错误类代表着不应该被捕捉的严重的问题 22 class RuntimeException 意味着程序出现问题了 21 Go 编辑 Go语言提倡的是错误处理 error handling Go语言设计者系统希望使用者在错误出时 显式地检查错误 23 Go虽然不提供与Java语言的try catch同等的功能语句 但是取而代之 提供了轻型的异常处理机制panic recover 24 NET语言 编辑 大多数 NET程序设计语言 内建的异常机制都是沿着函数调用栈的函数调用逆向搜索 直到遇到异常处理代码为止 而 Visual Basic 尤其是在其早于 net 的版本 例如 6 0 中 走得更远 on error 语句可轻易指定发生异常后是重试 resume 还是跳过 resume next 还是执行程序员定义的错误处理程序 goto 错误处理 编辑错误处理 error handling 是通过处理函数的返回值的形式从而处理错误的一种编程方式 在Go等返回值可为复数的语言中 可通过将其中一个值设为错误值 从而达到错误处理的效果 f err os Open filename ext if err nil log Fatal err do something with the open File f 在仅仅支持返回状态码的语言里 可通过处理错误码 达到错误处理的效果 shell语言可通过 获得函数执行的退出码 从而判断是否出错 在其他语言中 可以通过判断结果的某一个特征 从而达到错误处理部分的效果 但不意味着这些语言自身支持错误处理 如 Java等面向对象的语言往往会通过null值判断是否执行失败 但有时候也会通过异常处理判断是否执行失败 技术问题 编辑主条目 例外处理 编程 英语 Exception handling programming 未捕捉异常 编辑 如果一个异常抛出后 没有被捕捉 那么未捕捉异常 uncaught exception 将会在运行时被处理 进行该处理的例程叫 未捕捉异常处理器 uncaught exception handler 25 26 大部分的处理是终止程序并将错误信息打印至控制台 该信息通常包含调试用的信息 如 异常的描述信息 栈追踪 27 28 29 通常处于最高级 应用级别 的处理器 即便捕捉到异常也会避免终止自身 如 线程出现异常 主线程也不会终止 30 31 值得了解的是 在即便未捕捉异常导致了程序异常中断 如 异常没被捕捉 滚动未完成 没释放资源 程序仍旧能正常地顺序性地关闭 只要确保运行时系统能正常地运行 因为运行时系统控制着整个程序的执行 作为默认的未捕捉异常处理器是可以被替换的 不管是全局还是单线程的 新的未捕捉异常处理器可以尝试做这些事情 未捕捉异常导致关闭了的线程 使之重启 提供另一种方式记录日志 让用户报告未捕捉异常等等 在Java中 单一线程可以使用Thread setUncaughtExceptionHandler 32 全局可以用Thread setDefaultUncaughtExceptionHandler 33 在python中 可通过修改sys excepthook 34 异常的静态检查 编辑 检查性异常 编辑 Java的设计者设计了 35 检查性异常 Checked exceptions 36 当方法引发 检查性异常 时 检查性异常 将成为方法符号的一部分 例如 如果方法抛出了IOException 我们必须显式地使用方法符号 在Java中是try catch 如果不这样做的话将会导致编译时错误 异常安全 编辑 一段代码是 异常安全的 如果这段代码运行时的失败不会产生有害后果 如内存泄露 存储数据混淆 或无效的输出 异常安全可分成不同层次 失败透明 也称作 不抛出保证 代码的运行保证能成功并满足所有的约束条件 即使存在异常情况 如果出现了异常 将不会对外进一步抛出该异常 异常安全的最好的层次 提交或卷回的语义 或称作 强异常安全 或 无变化保证 运行可以是失败 但失败的运行保证不会有负效应 因此所有涉及的数据都保持代码运行前的初始值 37 基本异常安全 失败运行的已执行的操作可能引起了副作用 但会保证状态不变 所有存储数据保持有效值 即使这些数据与异常发生前的值有所不同 最小异常安全 也称作 无泄漏保证 失败运行的已执行的操作可能在存储数据中保存了无效的值 但不会引起崩溃 资源不会泄漏 没有异常安全 没有保证 最差的异常安全层次 例如 考虑一个smart vector类型 如C 的 std vector或Java的 ArrayList 当一个数据项x插入vector v 必须实际增加x的值到vector的内部对象列表中并且修改vector的计数域以正确表示v中保存了多少数据项 此时如果已有的存储空间不够大 就需要分配新的内存 内存分配可能会失败并抛出异常 因此 vector数据类型如果是 失败透明 保证将会非常困难甚至不可能实现 但vector类型提供 强异常安全 保证却是相当容易的 在这种情况下 x插入v或者成功 或者v保持不变 如果vector类型仅提供 基本异常安全 保证 如果数据插入失败 v可能包含也可能不包含x的值 但至少v的内部表示是一致的 但如果vector数据类型是 最小异常安全 保证 v可能会是无效的 例如v的计数域被增加了 但x并未实际插入 使得内部状态不一致 对于 异常不安全 的实现 程序可能会崩溃 例如写入数据到无效的内存 通常至少需要基本异常安全 失败透明是难于实现的 特别是在编写库函数时 因为对应用程序的复杂知识缺少获知 引用 编辑 abnormality汉语 繁体 翻译 剑桥词典 dictionary cambridge org 2020 02 04 原始内容存档于2021 04 14 中文 简体 Hardware Exceptions Detection TEXAS INSTRUMENTS 2011 11 24 2012 10 05 原始内容存档于2013 11 10 英语 Kiniry J R Exceptions in Java and Eiffel Two Extremes in Exception Design and Application Advanced Topics in Exception Handling Techniques Lecture Notes in Computer Science 4119 2006 288 300 ISBN 978 3 540 37443 5 doi 10 1007 11818502 16 Stroustrup C Style and Technique FAQ www stroustrup com 5 May 2018 原始内容存档于2 February 2018 Kiniry J R Exceptions in Java and Eiffel Two Extremes in Exception Design and Application Advanced Topics in Exception Handling Techniques Lecture Notes in Computer Science 4119 2006 288 300 ISBN 978 3 540 37443 5 doi 10 1007 11818502 16 6 0 6 1 Gabriel amp Steele 2008 第3頁 White 1979 第194頁 Stroustrup 1994 第392頁 Stroustrup 1994 16 6 Exception Handling Resumption vs Termination pp 390 393 C A R Hoare The Emperor s Old Clothes 1980 I have been giving the best of my advice to this project since 1975 At first I was extremely hopeful The original objectives of the language included reliability readability of programs formality of language definition and even simplicity Gradually these objectives have been sacrificed in favor of power supposedly achieved by a plethora of features and notational conventions many of them unnecessary and some of them like exception handling even dangerous Weimer W Necula G C Exceptional Situations and Program Reliability PDF 30 2 2008 原始内容存档 PDF 于2015 09 23 journal 被忽略 帮助 Frequently Asked Questions 2017 04 27 原始内容存档于2017 05 03 We believe that coupling exceptions to a control structure as in the try catch finally idiom results in convoluted code It also tends to encourage programmers to label too many ordinary errors such as failing to open a file as exceptional Panic And Recover 互联网档案馆的存檔 存档日期2013 10 24 Go wiki Weekly Snapshot History golang org 原始内容存档于2017 04 03 Proposal for an exception like mechanism golang nuts 25 March 2010 25 March 2010 原始内容存档于2013 03 06 Effective Go golang org 原始内容存档于2015 01 06 Roberts Eric S Implementing Exceptions in C PDF DEC Systems Research Center 21 March 1989 4 January 2022 SRC RR 40 8 Errors and Exceptions Python 3 8 1 documentation docs python org 2020 02 04 原始内容存档于2022 06 08 Python documentation Glossary EAFP What Is an Exception The Java Tutorials gt Essential Classes gt Exceptions docs oracle com 2020 02 04 原始内容存档于2022 06 09 21 0 21 1 Unchecked Exceptions The Controversy The Java Tutorials gt Essential Classes gt Exceptions docs oracle com 2020 02 04 原始内容存档于2022 06 07 Error Java Platform SE 8 docs oracle com 2020 02 04 原始内容存档于2021 10 24 Error handling and Go The Go Blog blog golang org 2020 02 04 原始内容存档于2021 07 12 Google 网上论坛 groups google com 2020 02 04 原始内容存档于2011 01 22 Mac Developer Library Uncaught Exceptions 互联网档案馆的存檔 存档日期2016 03 04 MSDN AppDomain UnhandledException Event 互联网档案馆的存檔 存档日期2016 03 04 Mac Developer Library Uncaught Exceptions 互联网档案馆的存檔 存档日期2016 03 04 The Python Tutorial 8 Errors and Exceptions 互联网档案馆的存檔 存档日期2015 09 01 Java Practices gt Provide an uncaught exception handler www javapractices com 5 May 2018 原始内容存档于9 September 2016 Mac Developer Library Uncaught Exceptions 互联网档案馆的存檔 存档日期2016 03 04 Exception Handling PyMOTW 3 pymotw com 2020 02 03 原始内容存档于2021 05 16 Thread setUncaughtExceptionHandler Thread setDefaultUncaughtExceptionHandler sys excepthook Google Answers The origin of checked exceptions 2011 12 15 原始内容存档于2011 08 06 Java Language Specification chapter 11 2 http java sun com docs books jls third edition html exceptions html 11 2 互联网档案馆的存檔 存档日期2006 12 08 存档副本 2011 08 13 原始内容存档于2009 02 03 参考文献 编辑Black Andrew P Exception handling The case against PDF 学位论文 University of Oxford January 1982 CiteSeerX 10 1 1 94 5554 nbsp OCLC 123311492 Gabriel Richard P Steele Guy L A Pattern of Language Evolution PDF LISP50 Celebrating the 50th Anniversary of Lisp 1 10 2008 ISBN 978 1 60558 383 9 doi 10 1145 1529966 1529967 Goodenough John B Structured exception handling Proceedings of the 2nd ACM SIGACT SIGPLAN symposium on Principles of programming languages POPL 75 204 224 1975a doi 10 1145 512976 512997 Goodenough John B Exception handling Issues and a proposed notation PDF Communications of the ACM 1975 18 12 683 696 CiteSeerX 10 1 1 122 7791 nbsp S2CID 12935051 doi 10 1145 361227 361230 Levin Roy Program Structures for Exceptional Condition Handling PDF 学位论文 Carnegie Mellon University June 1977 Template DTIC 原始内容存档 PDF 于December 22 2021 Stroustrup Bjarne The design and evolution of C 1st Reading Mass Addison Wesley 1994 ISBN 0 201 54330 3 White Jon L NIL A Perspective PDF Proceedings of the 1979 Macsyma User s Conference May 1979 Keeton Brian Cavaness Chuck Friesen Geoff Special Edition Using Java 2 Standard Edition Que Publishing 2001 ISBN 978 0 7897 2468 7 英语 外部链接 编辑A Crash Course on the Depths of Win32 Structured Exception Handling by Matt Pietrek Microsoft Systems Journal 1997 Article C Exception Handling by Christophe de Dinechin Article Exceptional practices by Brian Goetz Article Object Oriented Exception Handling in Perl by Arun Udaya Shankar Article Programming with Exceptions in C by Kyle Loudon Article Unchecked Exceptions The Controversy Conference slides Floating Point Exception Handling policies pdf p 46 by William Kahan Descriptions from Portland Pattern Repository Does Java Need Checked Exceptions 取自 https zh wikipedia org w index php title 异常处理 amp oldid 81812693, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。