2-异常处理机制
1.使用try...catch捕获异常
(1)当Java运行时环境收到异常对象时,会寻找能处理该异常对象的catch块,如果找到合适的catch块,则把异常对象交给该catch块处理,这个过程被称为捕获(catch)异常;
(2)如果java运行时环境找不到捕获异常的catch块,则运行时环境终止,Java程序也将退出;
(3)捕获异常的格式:
try{
//可能引发异常的代码
}catch(Exception e){
//处理异常
}
2.异常类的继承体系
(1)每个catch块都是专门用于处理该异常类及其子类的异常实例;
(2)当java运行时环境接收到异常对象后,会依次判断该异常对象是否是catch块后异常类或其子类的实例,如果是,将调用该catch块来处理该异常,如果不是,则再次拿该异常对象和下个catch块里的异常类进行比较;
(3)如果try块被执行一次,则在try块后只有一个catch块会被执行,绝不可能有多个catch块被执行。除非在循环中使用了continue开始下一次循环,下一次循环中又重新执行了try块,才可能导致多个catch块被执行,即try块执行多少次,catch最多被执行多少次;
(4)Java把所有的非正常情况分为异常(Exception)和错误(Error),他们都继承了Throwable父类,Error错误,一般是指与虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接失败等,这种错误不能被恢复或捕捉,将导致应用程序的中断;
(5)程序总是把Exception异常类的catch块放在最后,这是由于系统寻找对应catch块顺序决定的(自上而下),所以在捕获异常时,不仅要把Exception异常放在最后,还要注意父类异常应该放在子类异常后边(先捕获小异常,再捕获大异常),否则将引起编译错误。
3.多异常捕获
(1)一个catch块可以捕获多种类型的异常;
(2)使用一个catch块捕获多种类型的异常时需要注意如下两个地方:
1)捕获多种类型的异常时,多种异常类型之间使用“|”隔开;
2)捕获多种类型的异常时,异常变量有隐式的final修饰,因此程序不能对异常变量重新赋值;
(3)多异常捕获的示例:
//多异常捕获 //即一个catch捕获多个异常类型 public class Test1 { public static void main(String[] args) { try{ int a = Integer.parseInt(args[0]); int b = Integer.parseInt(args[1]); int c = a / b; System.out.println("两个数相除的结果是:"+c); } //一个catch同时捕获多种异常类型 catch(IndexOutOfBoundsException|NumberFormatException|ArithmeticException e){ System.out.println("发生数组越界、数字格式异常或算数异常之一"); //捕获多种异常时,异常变量默认有final修饰 //所以下面代码有错 //e = new ArithmeticException("test"); } //只捕获了一个异常,异常对象则没有被final隐式修饰 catch(Exception e){ System.out.println("未知的异常"); e = new RuntimeException("test"); } } }
4.访问异常信息
所有的异常对象都包含了下面几个常用的方法
1)getMessage():返回该异常的详细描述字符串;
2)printStackTrace();将该异常的跟踪栈信息输出到标准错误输出;
3)printStackTrace(PrintStream s):将该异常的跟踪栈信息输出到指定输出流;
4)getStackTrace();返回该异常的跟踪栈信息;
5.使用finally回收资源
(1)程序在try块中打开的一些物理资源(如数据库连接、网络连接和磁盘文件等),这些资源都必须显式的回收。
(2)finally块用于保证系统一定能够回收在try块中打开的物理资源;
(3)异常处理语法结构中只有try块是必须的,如果没有try块,则也不能有catch块和finally块;catch块和fianlly块是可选的,但catch块和finally块至少有一者出现,也可以同时出现;可以出现多个catch块;多个catch块必须位于try块之后,finally块必须位于所有catch块之后:
import java.io.FileInputStream; import java.io.IOException; public class Test2 { public static void main(String[] args) { FileInputStream fis = null; try{ fis = new FileInputStream("a.txt"); }catch(IOException e){ System.out.println(e.getMessage()); //return强制方法返回 虽然return类方法,但依然会执行finally块中的代码 return; //exit退出虚拟机 但如果使用System.exit(1)退出虚拟机,则finally块失去执行机会 //System.exit(1); }finally{ //关闭磁盘文件、回收资源 if(fis!=null){ try{ fis.close(); }catch(IOException e){ e.printStackTrace(); } } System.out.println("执行finally块中的资源回收"); } } }
(4)不要在finally块中使用如return或者throw等导致方法终止的语句,一旦在finally块中使用了return或者throw语句,将会导致try块、catch块中的return、throw语句失效。
6.异常处理的嵌套
异常处理流程代码可以放在任何能放可执行代码的地方,即完整的异常处理流程可存在于try块中、catch块中、finally块中。
7.自动关闭资源的try语句
(1)在try关键字后紧跟一对圆括号,圆括号里可以声明、初始化一个或多个资源,此处资源是指必须在程序结束时显式关闭的资源(如数据库连接、网络连接等),try语句在该语句结束时自动关闭这些资源;
(2)为保证try语句可以正常关闭资源,这些资源实现类必须实现AutoCloseable或Closeable接口,实现这两个接口就必须实现close()方法;
(3)自动关闭资源的try语句相当于包含了隐式finally块,因此这个try语句可以没有catch块,也没有finally块:
import java.io.BufferedReader; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; public class Test3 { public static void main(String[] args)throws IOException { try( //声明、初始化两个可关闭的资源 //try语句会自动关闭这两个资源 BufferedReader br = new BufferedReader(new FileReader("Test3.java")); PrintStream ps = new PrintStream(new FileOutputStream("a.text")) //注意最后一行没有分号 ){ //使用者两个资源 System.out.println(br.readLine()); ps.println("abcdefg"); } } }
(4)如果程序需要,自动关闭try语句后也可以带多个catch块和一个finally块。