(知识点很乱,当做笔记来看就可以了)

先以一个例子开头:在代码中,我们的程序可能被零除,这个时候有必要进行必要的检查,确保程序不会冒进。但是我们要怎么知道分母是零的呢?并且这种情况往往发生在意料之外,这个时候就需要产生一个异常,而不是继续执行下去。



异常产生时会发生几件事情。首先,按照与创建Java 对象一样的方法创建异常对象:在内存“堆” 里,使用new 来创建。随后,停止当前执行路径(记住不可沿这条路径继续下去),然后从当前的环境中释 放出异常对象的句柄。此时,异常控制机制会接管一切,并开始查找一个恰当的地方,用于继续程序的执 行。这个恰当的地方便是“异常控制器”(catch块),它的职责是从问题中恢复,使程序要么尝试另一条执行路径,要么简单地继续。 



假若有一个尚未初始化的对象引用a,在程序中

if(a == null) 
 throw new NullPointerException("t = null");

在这儿,关键字throw会象变戏法一样做出一系列不可思议的事情。它首先执行new表达式,创建一个不在程序常规执行范围之内的对象。而且理所当然,会为那个对象调用构建器。随后,对象实际会从方法中返回——尽管对象的类型通常并不是方法设计为返回的类型。为深入理解异常控制,可将其想象成另一种返回机制——但是不要在这个问题上深究,否则会遇到麻烦。通过“掷”出一个异常,亦可从原来的作用域中退出。但是会先返回一个值,再退出方法或作用域。但是,与普通方法返回的相似性到此便全部结束了,因为我们返回的地方与从普通方法调用中返回的地方是迥然有异的。




异常的捕获:

若某个方法产生一个异常,必须保证该异常能被捕获,并获得正确对待。对于Java的异常控制机制,它的一个好处就是允许我们在一个地方将精力集中在要解决的问题上,然后在另一个地方对待来自那个代码内部的错误。 


try{
//可能产生异常的代码块
}


而在使用了异常控制技术后,可将所有东西都置入一个try块内,在同一地点捕获所有异常。这样便可极大简化我们的代码,并使其更易辨读,因为代码本身要达到的目标再也不会与繁复的错误检查混淆。 (其实Java的异常机制,让代码的可读性极大的降低了)



产生的异常必须要在某个地方终止,那就是异常控制器:

catch(){}

而且针对想捕获的每种异常类型,都必须有一个相应的异常控制器。



异常还采用了一个额外的关键字:throws;后面跟随全部潜在的异常类型。以便礼貌地告诉程序员该方法会“掷”出什么异常,令对方方便地加以控制。这属于方法声明的一部分。



我们可创建一个控制器,令其捕获所有类型的异常。具体的做法是捕获基础类异常类型Exception(也存在其他类型的基础异常,但Exception是适用于几乎所有编程活动的基础)。如下所示: 


catch(Exception e) { 
System.out.println("caught an exception"); 
}

这段代码能捕获任何异常,所以在实际使用时最好将其置于控制器列表的末尾,防止跟随在后面的任何特殊异常控制器失效。




在某些情况下,我们想重新掷出刚才产生过的异常,特别是在用Exception捕获所有可能的异常时。由于我们已拥有当前异常的引用,所以只需简单地重新掷出那个引用即可。下面是一个例子: 


catch(Exception e) { 
System.out.println("一个异常已经产生"); 
throw e; 
}



重新“掷”出一个异常导致异常进入更高一级环境的异常控制器中。用于同一个try块的任何更进一步的catch从句会被忽略。此外,与异常对象有关的所有东西都会得到保留,所以用于捕获特定异常类型的更高一级的控制器可以从那个对象里提取出所有信息。




Java包含了一个名为Throwable的类,它对可以作为异常“掷”出的所有东西进行了描述。Throwable对象有两种常规类型(亦即“从Throwable继承”)。其中,Error代表编译期和系统错误,我们一般不必特意捕获它们(除在特殊情况以外)。Exception是可以从任何标准Java库的类方法中“掷”出的基本类型。此外,它们亦可从我们自己的方法以及运行期偶发事件中“掷”出。 




RuntimeException(或者从它继承的任何东西)属于一种特殊情况,我们不能捕获他,在发生运行时异常时,我们需要在自己的代码中寻找错误。




并不一定非要使用Java异常。这一点必须掌握,因为经常都需要创建自己的异常,以便指出自己的库可能生成的一个特殊错误。为创建自己的异常类,必须从一个现有的异常类型继承——最好在含义上与新异常近似。


class MyException extends Exception { 
  public MyException() {} 
  public MyException(String msg) { 
    super(msg); 
  } 
}

我们也可以为自建的异常类添加一些字段来更好的描述它。




覆盖一个方法时,只能产生已在方法的基础类版本中定义的异常。




无论一个异常是否在try块中发生,我们经常都想执行一些特定的代码。为达到这个目的,可在所有异常控制器的末尾使用一个finally从句。在没有“垃圾收集”以及“自动调用破坏器”机制的一种语言中,finally显得特别重要,因为程序员可用它担保内存的正确释放——无论在try块内部发生了什么状况。但Java提供了垃圾收集机制,所


以内存的释放几乎绝对不会成为问题。另外,它也没有构建器可供调用。既然如此,Java里何时才会用到finally呢? 除将内存设回原始状态以外,若要设置另一些东西,finally就是必需的。例如,我们有时需要打开一个文件或者建立一个网络连接,或者在屏幕上画一些东西,甚至设置外部世界的一个开关,等等。




异常匹配 :


“掷”出一个异常后,异常控制系统会按当初编写的顺序搜索“最接近”的控制器。一旦找到相符的控制


器,就认为异常已得到控制,不再进行更多的搜索工作。