Java :异常处理

异常的分类

异常的分类
非检查异常(unckecked exception):Error 和 RuntimeException 以及他们的子类。javac在编译时,不会提示和发现这样的异常,不要求在程序处理这些异常。所以如果愿意,我们可以编写代码处理(使用try…catch…finally)这样的异常,也可以不处理。对于这些异常,我们应该修正代码,而不是去通过异常处理器处理 。这样的异常发生的原因多半是代码写的有问题。如除0错误ArithmeticException,错误的强制类型转换错误ClassCastException,数组索引越界ArrayIndexOutOfBoundsException,使用了空对象NullPointerException等等。

检查异常(checked exception):除了Error 和 RuntimeException的其它异常。javac强制要求程序员为这样的异常做预备处理工作(使用try…catch…finally或者throws)。在方法中要么用try-catch语句捕获它并处理,要么用throws子句声明抛出它,否则编译不会通过。如SQLException , IOException,ClassNotFoundException 等。

简言之,RuntimeException的子类异常是代码本身的问题导致的,不期望使用异常处理。而Exception的直接子类应使用异常处理


异常处理

try{
    业务逻辑;
    业务逻辑;
    业务逻辑;//哪里发生异常就在哪里终止
    ......
}catch(异常类型1 e){//依次匹配,匹配时支持父类匹配
    处理1;//也可再次抛出throw e;
}catch(异常类型2 e){//抛出的异常被catch到,就不再往下匹配
    处理2;
}catch(异常类型3 e){
    处理3;
}finally{
    执行;
}

finally块不管异常是否发生,只要对应的try执行了,则它一定也执行。只有一种方法让finally块不执行:System.exit()。因此finally块通常用来做资源释放操作:关闭文件,关闭数据库连接等等

良好的编程习惯是:在try块中打开资源,在finally块中清理释放这些资源

  • 在catch中return

      使用try……catch……finally进行异常处理时,如果在某个catch中return,finally中的内容仍然会得到执行,在调试中可以看到,程序执行至return语句时,跳转至finally中,执行完后在回归至return执行,finally中的代码可以修改数据。然而return在先前已经产生,所以return的结果是finally未执行时的状态(finally中没有return)

示例
public class Main {

    private static String s = "";

    public static void main(String[] args) {
        System.out.println(test());
        System.out.println("s ;"+s);
    }

    private static String test(){
        int [] error = new int[5];

        try {
            System.out.println(error[5]);
        }catch (Exception e){
            System.out.println("捕捉到一只异常");
            s = "catch";
            return s;
        }finally {
            s = "finally";
        }
        return s;
    }

}
//输出为
捕捉到一只异常
catch
s :finally
  • catch、finally中均有return
    private static String test(){
        int [] error = new int[5];

        try {
            System.out.println(error[5]);
        }catch (Exception e){
            System.out.println("捕捉到一只异常");
            s = "catch";
            return s;
        }finally {
            s = "finally";
            return s;
        }
    }
//输出为
捕捉到一只异常
finally
s :finally

try、catch、finally中出现流程控制语句return、break、continue等会使程序流程十分诡异 参考Java 中的异常和处理详解

总之

  • 不要在fianlly中使用return
  • 不要在finally中抛出异常
  • 减轻finally的任务,不要在finally中做一些其它的事情,finally块仅仅用来释放资源是最合适的
  • 将尽量将所有的return写在函数的最后面,而不是try … catch … finally中

异常捕捉机制

Created with Raphaël 2.1.2异常抛出在try中?有对应的catch?执行catch并继续End退出到({})外层在函数中?返回调用者yesnoyesnoyesno

异常的抛出

  • 在方法首部声明可能抛出的异常
    • 由于Java的多态性,当子类重写父类的带有 throws声明的函数时,其throws声明的异常必须在父类异常的可控范围内,即用于处理父类的throws方法的异常处理,必须也适用于子类的这个带throws方法
  • 用try与catch包裹可能抛出异常的代码块
  • 手动抛出异常
    • throw new 异常类型();

异常与继承

  • 为了保证多态性下的父类变量不会遗漏处理某个子类方法特有的异常,子类重写父类的方法时,不能抛出比父类方法更多的异常
  • 子类的构造方法必须声明父类构造方法抛出的所有异常,因为子类构造方法会调用父类构造方法。
  • 子类构造方法可以抛出更多异常,因为构造方法的调用一般是直接的,至于子类的构造方法间接调用,已经由第二条保证

自定义异常

如果要自定义异常类,则扩展Exception类即可,因此这样的自定义异常都属于检查异常(checked exception)。如果要自定义非检查异常,则扩展自RuntimeException。

按照国际惯例,自定义的异常应该总是包含如下的构造函数:

  • 一个无参构造函数
  • 一个带有String参数的构造函数,并传递给父类的构造函数
  • 一个带有String参数和Throwable参数,并都传递给父类构造函数
  • 一个带有Throwable 参数的构造函数,并传递给父类的构造函数。

2018/7/28

2018/8/2更新

原文地址:https://www.cnblogs.com/kafm/p/12721853.html