异常

  • 一、分类
  • 1. Error
  • 2. Exception
  • 二、处理机制
  • 1. 捕获异常
  • 2. 抛出异常
  • 三、自定义异常类


一、分类

1. Error

2. Exception

  • 编译时异常
  • 运行时异常

二、处理机制

1. 捕获异常

  • try-catch-finally
try{
  //出现异常后,try块异常后面的代码不会再执行,直接跳转到catch块
}catch(Exception e){
  //只有出现异常才会执行
  //当要跳出catch块时,先去执行finally  
}finally{
  //无论是否出现异常都会执行
  //一般用来关闭资源
}
//处理完后程序 会 继续往下执行

练习一:当catch和finally都包含return语句,怎么执行

public class ExceptionDemo1{
  
  public static int method(){
    int i = 1;
    try{
      String name = null;
      if(name.equals("Tom")){
        System.out.println("name");
      }
    }catch(NullPointerException e){
      return 3;
    }finally{
      return 4;
    }
  }

  public static void main(String[] args){
    System.out.println(method());
  }
}
//答案是输出4
//因为无论如何finally都需要执行

练习二:当catch和finally都包含return语句,怎么执行

public class ExceptionDemo1{
  
  public static int method(){
    int i = 1;
    try{
      String name = null;
      if(name.equals("Tom")){
        System.out.println("name");
      }
    }catch(NullPointerException e){
      return ++i;
    }finally{
      return ++i;
    }
  }

  public static void main(String[] args){
    System.out.println(method());
  }
}
//catch块的return语句其实可以拆分为i++和return i
//当执行到return i时,因为finally必须执行,因此跳到finally继续执行代码
//finally同样可以拆分为i++和return i
//执行return的时候,退出方法
//输出结果是3

练习三:只有catch包含return语句,怎么执行

public class ExceptionDemo1{
  
  public static int method(){
    int i = 1;
    try{
      String name = null;
      if(name.equals("Tom")){
        System.out.println("name");
      }
    }catch(NullPointerException e){
      return ++i; 
    }finally{
      ++i;
      System.out.println("i="+i);
    }
  }

  public static void main(String[] args){
    System.out.println(method());
  }
}
//执行到catch的return时,先用临时变量存结果值,temp=2,然后跳转到finally。
//finally执行完成后,再回到catch中return
//输出结果是
//i=3
//2

练习四:try-catch-finally外包含return语句,怎么执行

public class ExceptionDemo1{
  
  public static int method(){
    int i = 1;
    try{
      String name = null;
      if(name.equals("Tom")){
        System.out.println("name");
      }
    }catch(NullPointerException e){
      return ++i; 
    }finally{
      ++i;
      System.out.println("i="+i);
    }
    return 5;
  }

  public static void main(String[] args){
    System.out.println(method());
  }
}
//在catch中return之后,就不会再执行try-catch-finally外的return
//输出结果同练习三



2. 抛出异常

  • try-finally
try{
  //出现异常后,try块异常后面的代码不会再执行,直接跳转到finally块
}finally{
  //无论是否出现异常都会执行
}
//处理完后程序 不会 继续往下执行,而是把异常抛给上一层方法

  • throws
    异常信息会一直往上层方法抛出,直到JVM打印出异常信息并终止程序
    方法调用:JVM > main() > f1() > f2()
  1. 当f2()发生编译时异常时,如果f2()不采用try-catch处理,并不会默认采用throws处理,必须要显式抛出异常
  2. 如果main(), f1()不采用try-catch处理,同样需要显示抛出异常
  3. 最后到JVM的时候,打印出异常信息并终止程序
public class ExceptionDemo1 {
  //3. 与步骤2相同
	public static void main(String[] args) throws FileNotFoundException {
		f1();
	}
	//2. f2()抛过来编译时异常,相当于f1()出现了编译时异常,也要指定异常处理方式
	public static void f1() throws FileNotFoundException{   
		f2();
    }
    //1. 出现编译时异常,抛到f1()   
    public static void f2() throws FileNotFoundException{   
        FileInputStream fi = new FileInputStream("C://test.txt");      
    }
}

细节:

  1. 对于编译时异常,程序并不会默认采用throws处理,必须显式指定处理的方式
  2. 对于运行时异常,程序如果不处理,默认采用throws方式
  3. 子类抛出的异常必须与父类的异常一致,或者是后者的子类
  4. 一个try-catch块可以捕获多个异常,catch的顺序应该时子异常类在先,父异常类在后
  5. 捕获异常相当于把异常留在当前类处理,通俗理解为一个人扛下了所有
  6. 抛出异常通俗理解为甩锅,try-finally也是一种甩锅,只不过甩锅之前要做点手脚(执行finally块)


三、自定义异常类

  1. 尽量继承运行时异常,这样可以采用默认处理机制,而编译时异常必须要处理
  2. 抛出自定义异常:
throw new CustomException
  1. throw关键字:手动生成异常类对象,也即人为制造错误,例如(int a = 1/0)