一、异常机制概述
1、异常机制包括的关键字
关键字 | 作用 |
---|---|
try | try块中编写业务处理代码 |
catch | catch块中编写异常处理代码 |
finally | finally块中一般用于物理资源的释放,此语句块总会被会被执行 |
throws | 在方法签名中使用,声明该方法可能抛出的异常 |
throw | 手动抛出一个具体的异常实例 |
2、语法结构
public void test()throws Exception{
try{
//可能出现异常的业务处理代码
throw new Exception();//手动制造异常
}catch(IOException e){
//异常处理代码
}catch(IndexOutOfBoundsException|RuntimeException e){
//异常处理代码,e隐式用final修饰
}finlly{
//资源释放等操作
}
}
3、说明
(1)throws后面可以声明多个异常,用“,”分隔。
(2)可以有多个catch块,原则:先捕获小异常,再捕获大异常。
(3)每对{}是一个独立的作用域,在try{}中声明的变量,不能在catch{}和finally{}中使用。
(4)Java7以后,同一个catch块可以捕获多种异常,用“|”分隔。此时,异常变量e隐式用final修饰,不能再重新赋值。
(5)通过异常变量e可以访问异常信息。
(6)Java的垃圾回收机制不会回收物理资源,如数据库连接,网络连接,磁盘文件等。这些连接必须在finally{}中显式关闭。Java异常机制总能保证finally{}被执行。但如果在try{}或catch{}中使用System.exit(1)语句来退出虚拟机,则不会执行finally{}语句块。
(7)catch块和finally块都是可选的,但catch块和finally块至少出现其中之一。
(8)一旦在finally块中 使用了return或throw语句,将会导致try块、catch块中的return、throw语句失效。但try块、catch块中return后的操作会被执行;如下:
public int test1(){
int i=0;
try {
return i++;
}finally {
return i;
}
}
public void test2(){
System.out.println(test1());//1
}
4、带资源的try语句
Java 7增强了try语句的功能,它允许在try关键字后紧跟一对圆括号,圆括号可以声明、初始化一个或多个资源,此处的资源指的是那些必须在程序结束时显式关闭 的资源(比如数据库连接、网络连接等),try语句在该语句结束时自动关闭这些资源。如下:
public void test() throws IOException {
try(FileInputStream f=new FileInputStream(new File("a.txt"));
FileReader fr=new FileReader(new File("b.txt"))){
System.out.println(f);
System.out.println(fr);
}
}
自动关闭资源的try语句相当于包含了隐式的finally块(这个finally块用于关闭资源),因此这个try语句可以既没有catch块,也没有finally块。
二、异常处理体系
Java将所有不正常情况分为两类:错误(Error)和异常(Exception)。
他们都继承了Throwable类。下面是常见异常类之间的继承关系:
Java语言规范将派生于Error类或RuntimeException类的所有异常称为未检查(unchecked)异常,所有其他的异常称为已检查( checked)异常。Java认为Checked异常都是可以在编译阶段被处理的异常,所以它强制程序处理所有的Checked异常;而Runtime异常则无须处理。
Error错误,一般是指与虚拟机相关的问题,如系统崩溃、虚拟机错误、动态链接失败、资源耗尽等,这种错误无法恢复或不可能捕获,将导致应用程序中断。通常应用程序无法处理这些错误,因此应用程序不应该试图使用catch块来捕获Error对象。
1、对于Checked异常有如下处理方式:
(1)使用try…catch语句捕获处理
(2)使用throws将异常抛出,由上一级方法调用者处理或继续向上抛出。main方法抛出的异常将交由JVM处理,JVM打印异常信息,并终止程序。
2、方法重写与异常处理
子类在重写父类的方法时,对于异常的处理有以下两个规则:
(1)子类方法声明处抛出的异常类型应与父类的相同或是其子类。
(2)子类方法声明抛出的异常不允许比父类抛出的多。
3、自定义异常类
自定义异常类非常简单,只需继承Exception类或RuntimeException类,并提供一个无参构造器和有参构造器即可。如下:
public class MyException extends Exception{
public MyException(){}
public MyException(String msg){
super(msg);
}
//可选,封装原始异常,实现对异常的链式处理
public MyException(Throwable t){
super(t);
}
}
4、使用throw语句抛出异常
对于如下代码:
try{
new FileInputStream("a.txt");
}catch(Exception ex){
throw ex;
}
在Java 7以前,Java编译器的处理“简单而粗暴”——由于在捕获该异常时声明ex的类型是Exception,因此Java编译器认为这段代码可能抛出Exception异常,所以包含这段代码的方法通常需要声明抛出Exception异常。
从Java 7开始,Java编译器会执行更细致的检查,Java编译器会检查throw语句抛出异常的实际类型,这样编译器知道ex 实际上只可能抛出FileNotFoundException异常,因此在方法签名中只要声明抛出FileNotFoundException异常即可。如下:
public void test()throws FileNotFoundException{
try{
new FileInputStream("a.txt");
}catch(Exception ex){
throw ex;
}
}