一、异常处理

1.结构

java.lang.Object

  |-----java.lang.Throwable

    |-----java.lang.Error:错误,java程序对此无能为力,不显式处理

    |-----java.lang.Exception:异常,需要进行处理

      |-----RuntimeException:运行时异常,较常见,可以不显式处理

        |-----ArrayIndexOutOfBoundsException/NullPointerException/ArithmeticException/ClassCastException

      |-----非RuntimeException:编译时异常,必须显式处理

2.处理方法——“抓抛模型”

(1)抛throw:当执行代码出现异常时,就在出现异常的代码处生成一个对应的异常类型的对象,并将其抛出(自动抛出/手动抛出),抛出后程序终止运行

(2)抓catch:抓住抛出的异常类的对象,准备对其进行处理

(3)处理方法一:

try{
    //可能出现异常的代码
}catch(Exception1 e){
    //对Exception1类型的异常的处理方式
  e.getMessage();//获取异常信息

  e.toString();//获取异常的名字加信息
  e.printStackTrace();//打印异常在堆栈中的信息:异常名称+异常信息+异常位置 }catch(Exception2 e){ //对Exception2类型的异常的处理方式 }finally{ //一定要执行的代码 }

注意事项:

A:try内声明的变量相当于局部变量,出了try{}语句就不能被调用

B:finally是可选的

C:多个catch语句时,抛出的异常从上往下匹配catch中的异常类型,满足就执行该catch内的代码,执行完跳过其他catch语句

D:异常处理完毕,其后的代码继续执行。

E:若catch中多个异常类型是包含的关系,必须把子类的catch语句放在父类的上面,否则报错。

F:finally语句的代码无论如何都会执行,除了System.exit(0);,即退出jvm。

(4)处理方法二:在方法的声明处,显式的抛出该异常对象的类型。

public void Test{
    public static void main(String[] args) throws FileNotFoundException,IOException{//继续将异常往上抛,交给虚拟机处理
        method2();
    }
    //public static void main(String[] args){//不往上抛了,直接对异常进行处理
    //        try{
    //        method2();
    //        }catch(Exception e){
    //            System.out,println(e.getMessage());
    //    }
    //}
    
    public static method2() throws FileNotFoundException,IOException{//继续往上抛,交给调用者main处理
        method1();
    }
    
    public static method1() throws FileNotFoundException,IOException{//异常往上抛,交给调用者method2处理
    FileInputStream fis = new FileInputStream(new File("hello.txt"));
    int b;
    while((b = fis.read()) != -1){
        System.out.println((char)b);
    }
    fis.close();
    }
}

A:格式:throws 异常类型

B:当一个方法可能生成某种异常,但不能确定如何处理这种异常,则此方法应显式的声明抛出异常,表明该方法不对该异常进行处理,由该方法的调用者负责处理。

C:异常的对象可以逐层往上抛,直到mian。在抛的过程中,可以通过try-catch-finally进行处理。

3.手动抛出异常:throw+异常对象

A:格式:throw new Exception1(参数);

4.自定义异常

(1)代码:

public class MyException extends RuntimeException{
    
    static final long serialVersionUID = -70348975766939L;
    
    public MyException(){
        
    }
    
    public MyException(String msg){
        super(msg);
    }
}

(2)特点:

A:自定义的异常类要继承现有的异常类,如RuntimeException、Exception,让类具有可抛性。

B:提供一个序列号,用于唯一确定一个异常类。

C:提供几个重载的构造器。

5.抛出异常的方法的重写规则

(1)子类重写父类的方法,其抛出的异常类型只能是父类方法的异常类的子类或异常类型一样。

(2)代码:

public class TestOverride{
    public static void main(String[] args){
        //调用method1时,编译时认为a是A类型的,应该抛出IOException,
        //而实际运行时a是B类型的,如果重写的method1抛出异常比父类方法的异常类型大,就会报错
        A a = new B();
        try{
            a.method1();
        }catch(IOException e){//
            e.printStackTrace();
        }
    }
}

class A{
    public void method1() throws IOException{
        
    }
}

class B exrends A{
    public void method1() throws FileNotFoundException{
        
    }
}

6.题目:下面代码的输出结果。

public Test{
    static void methodA(){
        try{
            System.out.println("进入方法A");
            throw new RuntimeException("手动制造异常");
        }finally{
            System.out.println("方法A的finally");
        }
    }
    
    static int methodB(){
        try{
            System.out.println("进入方法B");
            return 1;//有finally不能return
        }finally{
            System.out.println("方法B的finally");
            return 2;
        }
    }
    
    public static void main(String[] args){
        try{
            methodA();
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
        int i = methodB();//上面异常处理完,接着执行methodB
     System.out.println(i);//输出2
} }

结果:

进入方法A

方法A的finally

手动制造异常

进入方法B

方法B的finally

2