java-异常处理机制

一、异常处理类继承关系

1.1、继承关系
2.1、受查异常
3.1、非受查异常

The class Exception and any subclasses that are not also subclasses of RuntimeException are checked exceptions. Checked exceptions need to be declared in a method or constructor’s throws clause if they can be thrown by the execution of the method or constructor and propagate outside the method or constructor boundary.

二、处理非受查异常实现的两种方式

2.1、使用try-catch-finally方式处理异常

try{
    //功能:try代码块中放置可能发生异常的代码
    //如果在try这个代码块中没有出现异常,那么执行完代码块中的语句后会执行finally中的语句
    //如果在try这个代码块中出现异常,异常点之后的代码不会被执行,转到catch代码块中

}catch(Exception e){
    //每一个catch代码块用于捕获try代码块中出现的异常,或者是异常的子类
    //catch后面的括号定义了异常类型和异常参数。
    //如果try代码块中没有异常,那么catch代码块将不会被执行
    //如果catch子句抛出了异常,那么

}finally{
    //finally块是可选的,如果catch块存在,那么finally块可有可无;finally 主要用于流的关闭和数据库连接关闭操作
    //无论异常是否发生,异常块是否被处理,finally都会执行
    //一个try块至少要有一个catch块或者是finally块与之对应
}
2.1.1异常处理流程:

当try中发生异常时,将执行控制流从异常发生的地方转移到能够处理这种异常的地方;也就是说当一个函数的某条语句发生异常时,这条语句的下面的语句将不会被执行,执行流会匹配最近的异常处理代码块-catch代码块去执行。异常处理完成以后,执行流会接着在处理了这个异常代码块的后面继续执行,这种模式称之为终结异常处理模式。我们看一个demo

package Exception;

public class NumberFormatExceptionTest {
    public static void main(String[] args){
        String str = "1e";
        stringtoNum(str);

    }
    public static void stringtoNum(String str){
        Integer i = null;
        try{
            i = Integer.parseInt(str);
            System.out.println("转换成功");
        }catch(NumberFormatException e){
            System.out.println("执行catch处理异常");
        }finally{
            System.out.println("执行catch处理异常后执行了finally块");
        }
        System.out.println("catch代码块执行后继续执行了此条命令");
    }
}

输出结构

执行catch块处理异常
执行catch处理异常后执行了finallycatch代码块执行后继续执行了此条命令

我们从这里可以看到当转换异常发生时,代码块中异常点后面的语句没有被执行转而去执行了catch块中的语句,执行完以后去执行了finally块,最后执行代码块外码的语句。

2.1.2局部变量

try、catch、finally代码块中定义的局部变量只能在各自的代码块中使用,这是因为代码块一旦被执行,局部变量就会被JVM回收掉。

2.1.3异常捕获的继承关系和执行关系

每一个catch块处理一个异常,异常匹配的顺序是按照从上往下的方式寻找匹配的异常类,其中只有第一个匹配的catch块会得到执行。类型匹配不仅支持精确匹配,同样也支持父类匹配(父类异常可以匹配子类异常类)。如果一个try块下的多个catch块之间捕获的异常类之间有继承关系,应该将子类异常放在父类异常前面,否则编译时会报错。示例

package Exception;

public class TestException {
    public static void main(String[] args){
        divid(2,0);
    }
    public static void divid(int i,int j){
        try{
            int d = i/j;
        }catch(ArithmeticException e){
            System.out.println("异常发生捕获了ArithmeticException类");
        }catch(Exception e){
            System.out.println("异常发生捕获了Exception类");
        }
    }
}
异常发生捕获了ArithmeticException类

我们知道ArithmeticException是Eexception类的一个子类,我们catch精准的匹配了ArithmeticException之后执行代码块中的代码,后面的catch块不再执行。

2.1.4 finally和return之间的关系
package Exception;

/**
 * Created by luckyboy on 2018/8/3.
 */
public class FinallyAndReturn {
    public static void main(String[] args){
        f(2);
    }
    private static void  f(int num){
        try{
            System.out.println("point1");
            if(num ==1 )
                return ;
            System.out.println("point2");
            if(num == 2)
                return;
            System.out.println("point3");
            if(num == 3)
                return;
        }finally{
            System.out.println("finally");
        }
    }
}

输出结果

point1
point2
finally

从输出结果我们可以看到如果在finally块之前调用了return语句,那么finally语句也是会执行的。

2.2异常声明和对捕获的异常重新抛出

如果我们的方法代码中运行时可能会出现异常,如果我们想要将异常交给调用方法处理,那么我们可以在方法使用throws声明异常或者是在catch中重新抛出一个异常。

2.2.1使用printStackTrace()打印异常信息
2.2.2使用throws在方法上声明一个异常
2.2.3使用throw抛出捕获的异常
package Exception;

/**
 * Created by luckyboy on 2018/8/3.
 */
public class NumberFormatExceptionTest {
    public static void main(String[] args){
        String str = "1e";
        stringtoNum(str);

    }
    public static void stringtoNum(String str){
        Integer i = null;
        try{
            i = Integer.parseInt(str);
        }catch(NumberFormatException e){
            throw e;
        }finally{
            System.out.println("执行catch处理异常后执行了finally块");
        }
        System.out.println("代码块外main的异常");
    }
}

输出结果

执行catch处理异常后执行了finally块
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
    at java.lang.Integer.parseInt(Integer.java:580)
    at java.lang.Integer.parseInt(Integer.java:615)
    at Exception.NumberFormatExceptionTest.stringtoNum(NumberFormatExceptionTest.java:15)
    at Exception.NumberFormatExceptionTest.main(NumberFormatExceptionTest.java:9)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

从上面我们可以看出,如果我们string的格式不对的时候会出现异常,我们使用异常捕获的方式先捕获异常,然后将异常抛出给调用者自己处理。

2.2.4使用异常链重新抛出异常

如果我们捕获一个异常的时候想要抛出一个异常的同时,不能丢失之前异常的信息,那么这个时候我们就要使用异常链的方式将之前的异常信息包含在新抛出的异常之中。
Throwabl这个超类中提供了一个构造器将之前的异常添加进当前的异常,另外一个就是initCause方法传递参数

Throwable(Throwable cause)//传递异常类

public Throwable initCause(Throwable cause)//传递异常类

示例

三、自定义异常类

如果我们要自定义异常类,我们

四、类继承和异常处理

如果一个子类继承了父类,同时子类覆盖了父类的方法,如果父类声明了异常,那么子类只能抛出父类声明的的那些异常类

猜你喜欢

转载自blog.csdn.net/makeliwei1/article/details/81384486