什么是异常,我们为什么要关心它--The Java Tutorial--Exception第一节

原创 2003年11月12日 13:01:00

Trail: Essential Java Classes

Lesson: Handling Errors with Exceptions

什么是异常,我们为什么要关心它<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

单词“exception”是短语“exceptional event(异常事件)”的缩写,它定义如下:

定义:异常是程序在执行时发生的事件,它会打断指令的正常流程。

许多种类的错误将触发异常,这些问题从像硬盘(crash)坠毁这样的严重硬件错误,到尝试访问越界数组元素这样的简单程序错误,像这样的错误如果在java函数中发生,函数将创建一个异常对象并把他抛出到运行时系统(runtime system)。异常对象包含异常的信息,包括异常的类型,异常发生时程序的状态。运行时系统则有责任找到一些代码处理这个错误。在java技术词典中,创建一个异常对象并把它抛给运行时系统叫做:抛出异常(throwing an exception)。

当某个函数抛出一个异常后,运行时系统跳入了这样一个动作,就是找到一些人(译者注:其实是代码)来处理这个异常。要找的处理异常的可能的人(代码)的集合(set)是:在发生异常的方法的调用堆栈(call stack)中的方法的集合(set)。运行时系统向后搜寻调用堆栈,从错误发生的函数,一直到找到一个包括合适的异常处理器(exception handler)的函数。一个异常处理器是否合适取决于抛出的异常是否和异常处理器处理的异常是同一种类型。因而异常向后寻找整个调用堆栈,直到一个合格的异常处理器被找到,调用函数处理这个异常。异常处理器的选择被叫做:捕获异常(catch the exception)。

如果运行时系统搜寻整个调用堆栈都没有找到合适的异常处理器,运行时系统将结束,随之java程序也将结束。

使用异常来管理错误,比传统的错误管理技术有如下优势:

1.  将错误处理代码于正常的代码分开。

2.  沿着调用堆栈向上传递错误。

3.  将错误分作,并区分错误类型。

 

1. 将错误处理代码于正常的代码分开。

在传统的程序种,错误侦测,报告,和处理,经常导致令人迷惑的意大利面条式(spaghetti)的代码。例如,假设你要写一个将这个文件读到内存种的函数,用伪代码描述,你的函数应该是这个样子的:

readFile{

        open the file;                               //打开文件

        determine its size;                        //取得文件的大小

        allocate that much memory;          //分配内存

        read the file into memory;             //读文件内容到内存中

        close the file;                              //关闭文件

}

 

匆匆一看,这个版本是足够的简单,但是它忽略了所有潜在的问题:

n         文件不能打开将发生什么?

n         文件大小不能取得将发生什么?

n         没有足够的内存分配将发生什么?

n         读取失败将发生什么?

n         文件不能关闭将发生什么?

为了在read_file函数中回答这些错误,你不得不加大量的代码进行错误侦测,报告和处理,你的函数最后将看起来像这个样子:

随着错误侦测的建立,你的最初的7行代码(粗体)已经迅速的膨胀到了29行-几乎400%的膨胀率。更糟糕的是有这样的错误侦测,报告和错误返回值,使得最初有意义的7行代码淹没在混乱之中,代码的逻辑流程也被淹没。很难回答代码是否做的正确的事情:如果函数分配内容失败,文件真的将被关闭吗?更难确定当你在三个月后再次修改代码,它是否还能够正确的执行。许多程序员“解决”这个问题的方法是简单的忽略它,那样错误将以死机来报告自己。

对于错误管理,Java提供一种优雅的解决方案:异常。异常可以使你代码中的主流程和处理异常情况的代码分开。如果你用异常代替传统的错误管理技术,readFile函数将像这个样子:

注意:异常并不能节省你侦测,报告和处理错误的努力。异常提供给你的是:当一些不正常的事情发生时,将所有蹩脚(grungy)的细节,从你的程序主逻辑流程中分开。

另外,异常错误管理的膨胀系数大概是250%,比传统的错误处理技术的400%少的多。

 

2. 沿着调用堆栈向上传递错误。

异常的第二个优势是,可以沿着函数的调用堆栈向上报告错误。设想,readFile函数是一系列嵌套调用函数中的第四个函数:method1调用method2, method2 调用method3,最后method3调用readFile

如果只有method1对发生在readFile中的错误感兴趣。传统的错误通知技术迫使mothed2mothed3沿着调用堆栈向上传递readFile的错误代码,直到到达对错误感兴趣的mothed1

 

就像前面所了解到的,java运行时系统向后(baskward,也就是向上)搜寻调用堆栈,找到对处理这个异常感兴趣的函数。Java函数可以“躲开(duck)”任何在函数中抛出的异常,因此,允许函数穿越过调用堆栈捕获它。那个唯一对错误感兴趣的函数method1,将负责(worry about)侦测错误。

然而,就像你在伪代码中看到的,在“中间人(中间的函数methoed2method3)”忽略异常需要受到影响,一个函数如果要抛出一个异常,必须在函数的公共接口声明中使用throws关键字指定。因此,一个函数可以通知它的调用者自己会抛出什么样的异常,这样调用者就可以有意识的决定对这些异常做些什么。

再一次注意异常和传统错误处理方式,在膨胀系数和迷惑系数的区别。使用异常的代码更简洁,更容易理解。

3. 将错误分作,并区分错误类型。

异常(们)经常被划分成类别或组。例如,你可以想象一组异常,它们中每一个都表示关于数组操作的的特殊的异常:索引超出数组的范围,要插入的元素是错误的类型,要查找的元素不在数组中。而且,你能想象一些函数将处理所有这类的异常(关于数组的异常),其它一些函数将处理特殊异常(仅仅是无效索引异常)。

由于在java程序中所有的异常首先是一个对象,异常的分组和分类成为类继承自然而然的结果。Java异常必须是Throwable或者是Throwable子类的实例。就像你可以从其它java类继承一样,你也可以创建Thowable的子类,或者孙子类(从Thowable子类继承)。每个叶子节点(没有子类的类),代表一种特殊类型的异常,每个节点(node)(有一个或者更多子类的类)代表一组有关联的异常。

例如,在下列图表中,ArrayExceptionException的子类(Throwable的一个子类),它有三个子类。

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />CSDN_Dev_Image_2003-11-111406360.gif

InvalidIndexException ElementTypeException,和NoSuchElementException都是叶子类,它们都是在操作数组时发生的错误。捕获异常的一种方法是仅仅捕捉那些叶子类的实例。例如,一个异常控制器仅仅捕捉无效索引异常,它的代码像这个样子:

ArrayExecption是节点(node)类,代表你在操作数组时发生的任何错误,包括特定代表一个错误的所有子类中的任何一个。如果一个函数要一组或者一类异常,只要在在cathc语句中指定这些异常的超类(superclass)。例如,要捕捉所有数组异常而不指定具体类型,异常控制器将捕捉ArrayException

这个异常控制器将捕捉所有数组异常,包括InvalidIndexException, ElementTypeException, NoSuchElementException。你可以在异常控制器的参数e中找到异常的精确的类型。你甚至可以建立这样的异常控制器,它处理所有的Exception

上面出示的异常控制器实在时太通用了,这样做使你的代码处理太多的错误,需要处理许多你不希望处理的异常,因而不能正确的处理异常。通常我们不推荐写通用的异常处理器。

就像你看到的,你能创建一组异常,并处理这些异常以通用的方式;你也能指定异常类型去区分异常,并处理异常以精确的方式。

 

What’s Next?

现在你能懂得在java程序中使用异常的好处,现在到了学习怎样去用它们的时候了。

 

什么是异常,我们为什么要关心它

什么是异常,我们为什么要关心它 单词“exception”是短语“exceptional event(异常事件)”的缩写,它定义如下: 定义:异常是程序在执行时发生的事件,它会打断指令的正常流程。...
  • wangpei787636458
  • wangpei787636458
  • 2011年12月01日 22:33
  • 237

java为什么引入异常处理机制

0. 为什么要引入异常处理机制?      在异常机制引入之前,利用if…else,sysout和syserror的方式处理异常。异常处理是程序设计中一个非常重要的方面,也是程序设计的一大难点,从C...
  • cuidiwhere
  • cuidiwhere
  • 2012年11月01日 22:29
  • 4752

什么是异常? 在什么情况用异常处理机制?

什么事异常????     异常(exception) 是程序运行过程中发生的事件,  该事件可以中断程序指令的正常执行流程.   异常的处理机制(重点) 1当JAVA程序运行时出现问题时,系...
  • woshi2512901978
  • woshi2512901978
  • 2013年01月17日 23:02
  • 5684

算法分析的正确姿势

http://www.techug.com/post/how-hacker-buy-lottery.html [本专题会对常见的数据结构及相应算法进行分析与总结,并会在每个系列的博文...
  • sinat_30603081
  • sinat_30603081
  • 2017年11月24日 14:56
  • 81

算法—时间复杂度分析

解决同一个问题可以有很多种算法,比较评价算法的好坏,一个重要的标准就是算法的时间复杂度。现在研究一下插入排序算法的执行时间,按照习惯,输入长度LEN以下用n表示。设循环中各条语句的执行时间分别是c1、...
  • nomisshe
  • nomisshe
  • 2013年09月05日 15:23
  • 729

什么是连接池?我们为什么需要它?

本文由 ImportNew - 唐小娟 翻译自 Geekexplains。如需转载本文,请先参见文章末尾处的转载要求。 ImportNew注:如果你也对Java技术翻译分享感兴趣,欢迎加入我们的 J...
  • novelly
  • novelly
  • 2014年01月24日 20:32
  • 415

我们为什么要学习JAVA?

有人说,JAVA已死,学JAVA还有前途吗?      真的是这样吗?       “JAVA已死”的论断从12年前就反复有人提,但是直到今天,JAVA毅然活着,2015年还荣登TIOBE指数的编...
  • LS1910831673
  • LS1910831673
  • 2016年11月04日 19:26
  • 924

我们为什么要上大学?

我们为什么要上大学?如果我是当着你的面问你,估计没有几个人能不假思索的回答出来,或者很多大学生都没用想过为什么要上大学,或者有人回答,别人都说上大学会有好的前途,或者别人都去上,所以我也要去上,如果你...
  • do_bset_yourself
  • do_bset_yourself
  • 2016年05月03日 11:42
  • 873

别再关心AI怎么好了,我们要搞懂AI怎么用

本文转自:脑极体在今天的中国,想要了解AI,最怕的是什么?答案也许只有一个,那就是开会。如今的人工智能大会基本是有套路的:首先要提问AI到底会不会取代人类;然后各个专家发言,畅想一下AI的美好未来;最...
  • zkh880loLh3h21AJTH
  • zkh880loLh3h21AJTH
  • 2018年02月02日 00:00
  • 30

从头认识Spring-1.1 什么是依赖注入?为什么需要依赖注入?

这一章节我们来讨论一下什么是依赖注入?为什么需要依赖注入?1.什么是依赖注入?笔者理解的是:对象的生成不再是通过显示的new,而且到spring容器里面取,对象的创建是使用注入这种形式2.为什么需要依...
  • raylee2007
  • raylee2007
  • 2016年01月29日 10:39
  • 5265
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:什么是异常,我们为什么要关心它--The Java Tutorial--Exception第一节
举报原因:
原因补充:

(最多只允许输入30个字)