异常的处理方法
一、Java的异常处理机制:
在 Java的异常处理机制为:抛出异常,捕捉异常。
- 抛出异常:方法中出现异常时,方法会创建对应的异常对象并交付运行时系统,这个异常对象中包含了异常类型和各种异常出现时的异常信息。运行时系统则主要负责寻找处置异常的代码并执行。
- 捕获异常:在方法抛出异常之后,运行时系统将转为寻找合适的异常处理器(exception handler)。潜在的异常处理器是异常发生时依次存留在调用栈中的方法的集合。当异常处理器所能处理的异常类型与方法抛出的异常类型相符时,即为合适 的异常处理器。运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。
一个方法所能捕捉的异常,一定是Java代码在某处所抛出的异常。简单地说,异常总是先被抛出,后被捕捉的。
Java规定,对于可查异常必须捕捉、或者声明抛出。允许忽略不可查的RuntimeException
和Error
。
以上内容引用自: 异常处理的机制。
二、 try - catch - finally :
利用 try-catch-finally
可以捕获及处理异常,其语法格式如下:
try{
//尝试运行的代码
}catch(异常类型 | 异常的变量名){
//异常处理代码
}finally{
//必定会执行的代码
try{}
语句块:try{}
内是要尝试运行的代码,是受异常监控的区域,发生异常会抛出相应的异常对象。catch(异常类型 | 异常的变量名){}
语句块:- 当
try{}
中发生异常,就要到catch
中找对应的异常类,并执行相应的执行代码。如果catch(){}
中没找到,异常会从try
语句块中抛出,让外层处理。 catch(){}
语句块是带参数的,就是可捕获的异常类型,如catch(Exception e)
。catch语句可以有多个,但catch 的范围只能从低到高(子类到父类),只要出现父类,下面的catch语句就不能再出现其子类,如出现
Exception
后就不能出现Exception
的子类://编译通过,后面的catch类型不能比上一个catch类型低 try { System.out.println(a/b); } catch (ArithmeticException e) { System.out.println("被除数不能为0"); } catch (NullPointerException e) { System.out.println("NullPointerException"); } catch (Exception e){ System.out.println("Exception"); } catch (Error e){ System.out.println("Error"); } catch (Throwable t){ System.out.println("Throwable"); } finally { System.out.println("最后处理"); } //编译不通过,报错 ArithmeticException 是 Exception 子类 try { System.out.println(a/b); } catch (Exception e) { System.out.println("Exception"); } catch (ArithmeticException e){ System.out.println("ArithmeticException"); } finally { System.out.println("最后处理"); }
当catch 命中相应的异常类型,就会执行相应的异常处理代码,并跳过后面的catch语句,直接走finally语句。
- 当
只要有
finally{}
语句块,只要程序不被强行终止,里面的代码就一定会被执行。即便出现 break, return等流程控制语句也一样要执行finally
语句。```java package com.zctou.exception; public class Demo01 { public static void main(String[] args) { int a = 1; int b = 0; try { System.out.println(a/b); } catch (ArithmeticException e) { System.out.println("被除数不能为0"); } finally { System.out.println("最后处理"); } } } //输出: 被除数不能为0 最后处理
finally 不管前面的异常怎么样都会执行,多用于处理善后的事宜,如关闭数据库,关闭文件读取IO流等。
- 有
try
就必须至少要有一个catch()
或finally
语句块。
三、异常抛出 throw 和 throws
抛出异常:异常把异常对象通过向调用层抛出,一层层向上抛直至传递给java虚拟机处理,称为抛出异常。
抛出异常有两种情况:一种是在方法体中主动抛出,另一种则是在方法声明时抛出异常。主动抛出异常,在方法里用关键字throw
,在方法声明中用关键字throws
。
方法体中抛出异常,关键字
throw
,格式如下:throw new 异常对象
示例:
package com.zctou.exception; public class Demo02 { public static void main(String[] args) { new Demo02().devided(1,0); } //定义除法,如果被除数为0, 主动抛 ArithmeticException 出异常 public void devided(int a, int b) { if(b==0) { throw new ArithmeticException(); // 文体中主动抛出一个对象 } System.out.println(a/b); } } //输出: Exception in thread "main" java.lang.ArithmeticException at com.zctou.exception.Demo02.devided(Demo02.java:11) at com.zctou.exception.Demo02.main(Demo02.java:6)
在方法声明中抛出异常,关键字
throws
,格式如下:throws 异常类型
示例:
package com.zctou.exception; public class Demo03 { public static void main(String[] args) { try { new Demo03().devided(1,0); } catch (ArithmeticException e) { System.out.println("外层处理异常"); e.printStackTrace(); } } //假设这个方法内处理不了或者不想处理异常,方法声明中用`throws`抛出异常 public void devided(int a, int b) throws ArithmeticException{ System.out.println(a/b); } } //输出: 外层处理异常 程序不会停止 java.lang.ArithmeticException: / by zero at com.zctou.exception.Demo03.devided(Demo03.java:17) at com.zctou.exception.Demo03.main(Demo03.java:7)
- 不受检异常(RuntimeException):在方法内主动抛出,函数上不用重复声明抛出。
- 若在方法声明中主动抛出异常,调用方法时,不用try-catch-finally处理。
小结:
- throws用于对方法进行声明,如果不声明throws,那么一般的Exception都要在这个方法中处理掉,否则编译发生错误。
- 如果方法声明了throws,可以交给上一级方法处理,但有些Exception可以不用catch捕获,编译也会通过。