一、异常体系
java异常源自超类throwable,细分为error和exception,error表示出现jvm级别的问题,该类问题对系统而言无法恢复不可捕捉,一旦出现,程序中断,不能进行处理;exception则表示出现的异常可以进行捕捉并做处理,又细分为运行时异常和编译时异常。
二、关键字和异常链
- 关键字
java异常体系中所涉及的关键字有try、catch、finally、throw、throws。
try:try块用于包含出现或可能出现异常的程序代码;
catch: catch块用于捕捉并处理try块中出现的异常对象,如果没有catch块,则会把异常对象提交给java虚拟机;
finally:只要在finally之前的程序没有出现退出jvm的行为(例如:System.exit(1);),则finally块一定会被执行,需要注意的是,如果finally块中出现return或者throw语句,则会覆盖掉try块和catcher块中的return和throw;
throw:如果捕捉到的异常不想立即处理或异常为自定义抛出异常,则可以利用关键字throw将该异常抛出给调用者,即在异常链中抛出一个异常对象给调用者,要注意的是如果抛出的是编译时异常,则还需要在方法声明处使用throws声明该方法会抛出的异常类型或加上try块;
throws:如果不想在方法中处理可能出现的异常,则在方法前声明该方法可能会抛出的异常,方便传递异常链;
关键字使用的示例如下代码所示。
package exception;
public class Demo {
/*
* 方法通过throws关键对外声明可能抛出的异常,调用者调用方法的时候必须显示的try起来
* 否则也应该继续对外抛出异常
*/
public void exceptionDemo()throws NullPointerException {
try {
/*
* 可能引发异常的语句要包含在try块中
*/
throw new NullPointerException("空指针异常");
} catch (Exception e) {
// TODO: handle exception
/*
* try块中发生的异常将会被JVM封装成一个异常对象传递到catch代码块中来进行处理
*/
} finally {
/*
* 无论是否在try块或者catch块中return,finally都会被执行而且会在return语句之前执行
* 除非在finally代码块之前出现了退出虚拟机的代码,例如System.exit(1);,否则finally一定会被执行
*/
}
}
}
- 异常链
异常冒泡机制:当一个异常对象产生了以后,会按照其被调用的层次进行冒泡,只到被try-catch处理或抛至虚拟机。
当发生或可能发生的异常对象不愿意立即处理,则可以利用throws或throw关键进行异常对象抛出,直道调用的最上层或抛给虚拟机。
三、编译时异常和运行时异常
编译时异常一般是资源类(例如io、数据库等),java认为编译时异常都是可以被处理恢复的,必须显式处理完成才能通过编译——没有完善错误处理的代码就根本不会被执行;而运行时异常则是在运行中表现出来,运行时异常都是RuntimException或其子类。
四、java7新特性
- 多异常捕获
java7以前的异常捕获,要求按照异常对象的范围从小到大的catch出来,但在java7中可以用“|”隔开,在同一个catch块中被捕获,但是这些异常对象隐士的含有final修饰,因此不能在被重新赋值,示例代码如下。
package exception;
public class ExceptionDemo {
public void show(boolean flag){
try{
if(flag){
throw new IndexOutOfBoundsException();
}else{
throw new NumberFormatException();
}
} catch (IndexOutOfBoundsException | NumberFormatException e){
/*
* catch块中用”|”分隔多个异常
*/
}
}
}
- 自动关闭资源的try语句
java7以前操作io等需要非内存资源的对象时,需要在try块中声明然后再finally块中关闭,java7新特性自动关闭资源的try语句能够减少程序员的代码量,前提是该类实现了Closeable或AutoCloseable接口,示例代码如下。
package exception;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class ExceptionDemo {
public void fileRead(String fileName){
try (
BufferedReader br = new BufferedReader(new FileReader(new File(fileName)));
){
/*
* 正常执行语句
*/
}catch (Exception e) {
// TODO: handle exception
/*
* 处理异常语句
*/
}
/*
* 省略了finally语句,java7新特性,当执行完语
*/
}
}
五、自定义异常
一般来说,用户自定义异常都应该继承Exception基类,如果希望Runtime异常类型,则应该继承RuntimeException基类,在自定义异常中,一般要含有无参构造函数,示例代码如下。
package exception;
public class MyException extends Exception {
private static final long serialVersionUID = 1L;
public MyException() {
// TODO Auto-generated constructor stub
}
public MyException(String msg){
super(msg);
}
}
六、例证
try块后面至少跟一个catch块或finally块,可以跟多个catch块,即最简单的异常处理语句为try{}catch(Exception e){};或try{}finally{},前者表示处理了异常,程序会继续往下执行,后者表示异常将会被抛给虚拟机,执行外finally块之后程序将不会继续往下执行,示例代码如下。
package exception;
/**
* @author reliveIT
*
* 本例的用以是测试没有捕捉异常块信息,程序是否还会继续往下执行,即没有catch块,程序是否还会继续往下执行
*/
public class Test_no_catch {
/*
* 该方法try块中将出现空指针异常,但是没有catch块捕捉以及处理
*/
public void findExceptionNotCatch() {
String str = null;
try {
System.out.println(str.length());// 该句将出现异常
} finally {
System.out.println("我是fendExceptionNoCatch方法的finally,try块出现了异常,程序是否还会继续执行下一个方法呢?");
}
}
/*
* 前一个方法中出现异常但是没有捕捉处理,该方法用于测试在这样的条件下是否还会被执行
*/
public void showNextStr() {
System.out.println("我被执行了!!!");
}
/*
* public Test_no_catch(){ this.findExceptionNotCatch(); this.showNextStr();
* }
*/
public static void main(String[] args) {
/*
* 主函数中先执行会抛出异常的方法findExceptionNotCatch,该异常捕获后没有进行处理
* 检测是否继续往下执行showNextStr方法
*/
Test_no_catch demo = new Test_no_catch();
demo.findExceptionNotCatch();
demo.showNextStr();
}
}
执行结果表示当执行findExceptionNotCatch方法发生了异常但是又未处理该异常,此时showNextStr方法将不会继续被执行,执行结果如下。
附注:
本文如有错漏之处,烦请不吝指正,谢谢!