1、异常的简介

通俗的来说,有异于常态,和正常或者说期望的结果的情况不一样。但是,异常有别于错误。
从编程的角度讲,把阻止当前方法或作用域继续执行的问题,称之为异常。

2、异常的处理:try-catch以及try-catch-finally

Java中采用try-catch或try-catch-finally这样的语句来处理异常。注意,不管是否有异常发生,finally块中的代码都会执行。

try{
   //会抛出异常的方法
}catch(Exception e){
   //处理该异常的代码块
}finally{
   //释放一些资源等
}

问:如果try语句块中的方法的确抛出异常了,将会发生什么情况呢?
答:首先,抛出异常的方法会终止执行;
然后,程序的控制权将被移交给catch块中的异常处理程序来进行处理,
而catch块中的处理异常的程序如何写,将根据不同的情景、业务来不同的对待。
例如,可以进行错误日志的记录;打印一些异常信息等等。
最后,程序继续执行finally块中的语句(如果有finally块的话),接着
try-catch-finally之外的语句会顺序的继续执行。

问:如果try语句块中会抛出很在多种类型的异常,这时该怎么办呢?
答:首先,针对不同类型的异常的处理方法不尽相同,就不能使用一个catch块来处理所有的异常。
这时,就需要使用多重catch语句块来处理这些异常。即,在try块后,用多个catch块来捕获
不同类型的异常进行分别处理。

try{
   //方法一,抛出第一种异常
   //方法二,抛出第二种异常
}catch(子类异常 e){
   //处理子类异常的代码块
}catch(父类异常 e){
   //处理父类异常的代码块
}catch(Exception e){
   //处理不知名的异常的代码块
}finally{
   //释放一些资源等
}

注意:处理异常顺序为,先catch子类异常,后catch父类异常。即,先子类后父类的顺序编写catch语句块。
这是因为,当异常发生时,异常处理系统会就近寻找匹配该异常的catch语句(即异常处理程序)。

由于子类继承与父类,针对父类异常的处理程序对于子类的异常也是适用的。这时,如果处理父类异常的catch写在子类异常的catch之前的话,
异常处理系统执行步骤就不会到达子类异常的catch块。

注意:有return的情况下try catch finally的执行顺序(最有说服力的总结)

3、抛出异常

问:如何抛出异常?
答:会使用到两个关键字:throw、throws。这二者有有很明显的区别。首先,是使用的位置不同,throws 只能跟在方法名和括号的后面,
而 throw 只能出现在方法体内。其次,throws 是一个声明(它声明这里可能出现异常,但未必一定出现。可抛出多个异常,用逗号隔开即可),
而 throw 是一个动作(它抛出也可以说它产生一个异常出现,只要执行到了这个关键字,异常必定出现)。当使用 throw 抛出(产生)一个异常的时候,如果方法用
throws 抛弃(该方法就不处理了)异常,那么这个异常将被抛到了调用这个方法的地方去。如果这个方法没有用 throws 抛弃异常,那么就需要使用 try…catch 来捕捉异常了。

public void 方法名(参数列表) throws 异常列表 {
    //如果该方法不处理这些可能存在的异常,可继续抛出,让更上一层的调用者来处理。
    throw new Exception();
}

4、自定义异常

顾名思义,就是自己定义的异常类型。这个类型必须继承与Java标准类库中意思相近的异常,或者直接继承所有异常的基类Throwable,
或者继承于基类Exception、Error。

自定义异常的基本格式:
class 自定义异常类型 extends 异常类型{
}

编写自己的异常类时需要记住下面的几点。
(1)所有异常都必须是 Throwable 的子类。
(2)如果望写一个检查性异常类,则需要继承 Exception 类。
(3)如果想写一个运行时异常类,则需要继承 RuntimeException 类。

例如,一个继承于Exception的自定义异常类:

package com.he.ing;
public class SelfDefException extends Exception {
    //无参构造器,很多时候会用到无参构造器
    public SelfDelException(){
    }
    //含参构造器
    public SelfDefException(String massage){
        super(massage);
    }
    public SelfDelException(Throwable cause){
        super(cause);
    }
    public SelfDelException(String massage,Throwable cause){
        super(massage,cause);
    }
}

备注:自定义异常的好处、会产生什么的后果

5、异常链

在《Java编程思想》中写到:
(1)常常会再捕获一个异常后跑出另外一个异常,并且希望把异常原始信息保存下来,这被称为异常链。
(2)在JDK1.4以前,程序员必须自己编写代码来保存原始异常信息。
(3)现在所有Throwable的子类子构造器中都可以接受一个cause对象作为参数,这个cause就异常原由,代表着原始异常,即使在当前位置创建并抛出行的异常,也可以通过这个cause追踪到异常最初发生的位置。
(4)在Throwable子类中,只有Error,Exception,RunimeException提供了带cause参数的构造器,其他的所以异常就只有通过initCause()来设置cause了。

6、使用异常的实验总结

(1)处理异常时,采用逻辑去合理规避的同时辅助try-catch来处理;
(2)在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常;
(3)对于不确定的代码,也可以加上try-catch,处理潜在的异常;
(4)尽量去处理异常,切记只是简单的调用printStackTrance()去打印输出;
(5)尽量添加finally语句块去释放占用的资源。