异常操作
异常操作
捕获异常
使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。try/catch 代码块中的代码称为保护代码,使用 try/catch 的语法如下:
try
{
// 程序代码
}catch(ExceptionName e1)
{
//Catch 块
}
Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。
譬如下面的例子中声明有两个元素的一个数组,当代码试图访问数组的第三个元素的时候就会抛出一个异常。
// 文件名 : ExcepTest.java
import java.io.*;
public class ExcepTest{
public static void main(String args[]){
try{
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown :" + e);
}
System.out.println("Out of the block");
}
}
/**
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block
**/
对于异常的捕获不应该觉得方便而将几个异常合成一个 Exception 进行捕获,比如有 IO 的异常跟 SQL 的异常,这样完全不同的两个异常应该分开处理!而且在 catch 里处理异常的时候不要简单的 e.printStackTrace(),而是应该进行详细的处理。比如进行 console 打印详情或者进行日志记录。
多重捕获块
一个 try 代码块后面跟随多个 catch 代码块的情况就叫多重捕获。多重捕获块的语法如下所示:
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}
上面的代码段包含了 3 个 catch 块。可以在 try 语句后面添加任意数量的 catch 块。如果保护代码中发生异常,异常被抛给第一个 catch 块,如果抛出异常的数据类型与 ExceptionType1 匹配,它在这里就会被捕获。如果不匹配,它会被传递给第二个 catch 块,如此,直到异常被捕获或者通过所有的 catch 块。
try {
file = new FileInputStream(fileName);
x = (byte) file.read();
} catch(FileNotFoundException f) { // Not valid!
f.printStackTrace();
return -1;
} catch(IOException i) {
i.printStackTrace();
return -1;
}
异常抛出
如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
public void test() throws Exception {
throw new Exception();
}
从上面这一段代码可以明显的看出两者的区别。throws 表示一个方法声明可能抛出一个异常,throw 表示此处抛出一个已定义的异常(可以是自定义需继承 Exception,也可以是 java 自己给出的异常类)。下面方法的声明抛出一个 RemoteException 异常:
import java.io.*;
public class className
{
public void deposit(double amount) throws RemoteException
{
// Method implementation
throw new RemoteException();
}
//Remainder of class definition
}
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。例如,下面的方法声明抛出 RemoteException 和 InsufficientFundsException:
import java.io.*;
public class className
{
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException
{
// Method implementation
}
//Remainder of class definition
}
finally 关键字
finally 关键字用来创建在 try 代码块后面执行的代码块。无论是否发生异常,finally 代码块中的代码总会被执行。在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。finally 代码块出现在 catch 代码块最后,语法如下:
try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}finally{
// 程序代码
}
其示例如下:
public class ExcepTest{
public static void main(String args[]){
int a[] = new int[2];
try{
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown :" + e);
}
finally{
a[0] = 6;
System.out.println("First element value: " +a[0]);
System.out.println("The finally statement is executed");
}
}
}
/**
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3
First element value: 6
The finally statement is executed
**/
注意,catch 不能独立于 try 存在、在 try/catch 后面添加 finally 块并非强制性要求的、try 代码后不能既没 catch 块也没 finally 块、 try, catch, finally 块之间不能添加任何代码。
finally 与 return
若有 finally 则在 catch 处理后执行 finally 里面的代码。然而存在这样两个问题:
try{
//待捕获代码
}catch(Exception e){
System.out.println("catch is begin");
return 1;
}finally{
System.out.println("finally is begin");
}
在 catch 里面有一个 return,那么 finally 会不会被执行呢?答案是肯定的,上面代码的执行结果为:
catch is begin
finally is begin
也就是说会先执行 catch 里面的代码后执行 finally 里面的代码最后才 return1;而如下的代码:
try{
//待捕获代码
}catch(Exception e){
System.out.println("catch is begin");
return 1;
}finally{
System.out.println("finally is begin");
return 2 ;
}
返回的是 return 2;原因很明显,就是执行了 finally 后已经 return 了,所以 catch 里面的 return 不会被执行到。也就是说 finally 永远都会在 catch 的 return 前被执行。