Java异常处理机制
更新日期:
异常允许我们强制停止程序运行,并告诉我们出现了什么问题,或者强制程序去处理问题,并返回到稳定状态。
Java提供一个Throwable类,该类是所有异常和错误类的超类。只有当对象是此类的实例时,才能通过Java虚拟机或者Java的throw语句抛出。throwable类及其子类的结构图:
一、异常类型
Error:一般是指严重的系统错误,与虚拟机相关的问题,如系统崩溃,虚拟机出错,动态链接失败等,这一类的错误一般无法修复或不可能捕获,将导致应用程序中断。
Exception:是指一些可以捕获且可能恢复的异常情况,如数组下标越界ArrayIndexOutOfBoundsException、数字被零除产生异常ArithmeticException、输入输出异常IOException等。
可以知道Error属于JVM需要负担的责任,RuntimeException类是程序应该负担的责任,受检异常是具体应用负担的责任。作为程序员关心的就是Exception。
1、非受检异常
是指编译器不要求强制处置的异常,一般是编程时的逻辑错误,是程序员应该避免的,RuntimeException类以及他的子类都是非受检异常的,具体如下:
1)错误的类型转换:ClassCastException
2)组下标越界:ArrayIndexOutOfBoundsException
3)空指针访问异常:NullPointerException
4)被零除产生异常:ArithmeticException
2、受检异常
编译器要求必须处置的异常,及程序运行时由于外界因素造成的一般性异常,具体如下:
1)没有找到具体指定名称的类异常:ClassNotFoundException
2)访问不存在的文件异常:FileNotFoundException
3)操作文件异常:IOException
4)操作数据库时发生异常:SQLException
Java要求Java程序必须捕获或声明所有的受检异常,对于这类异常,如果程序不做处理,则将会带来意想不到的结果,而非受检异常可以不做任何处理。
二、捕获异常语句
1、try……catch……finally……
try选定要捕获异常的范围,在执行时,catch后面括号内的代码会产生异常对象并抛出,然后用catch块来处理异常。
finally不管是否有异常发生都要执行的语句块,如数据库的关闭。要注意:如果try语句块中有一个明确的return语句,finally快也总是在return前执行。
2、throws 和 throw
throw:语句明确的抛出一个异常,必须是一个throwable 的类,或者new来创建一个实例:throw new XXException();
执行throw语句后,运行流程将立即停止throw的下一条语句也将暂停执行。
throws:如果一个方法a可以引发异常,而他本身并不对该异常进行处理,那么a方法必须将这个异常抛给调用方法,以使程序能够继续执行下去。用法:method()throws Exception1,Exception2,。即throws用来声明一个方法可能会抛出的所有异常,如果一个方法声明的是受检异常,那么调用这个方法的类必须处理这个异常。可以使用try……catch……来捕获,也可以在该方法上声明throws。
public static void main(String[] args) {
// TODO Auto-generated method stub
int number = 0;
try {
System.out.println("aaaaaaaa");
number = Integer.parseInt(args[0]);
System.out.println("bbbbbbbb");
} catch (Exception e) {
// TODO: handle exception
throw new ArrayIndexOutOfBoundsException("out of bounds");
//System.out.println("非法的数字");
}
finally{
System.out.println("你输入的数字为:"+number);
}
}
结果:
aaaaaaaa
你输入的数字为:0
Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException:
out of boundsat com.wt.others.ThrowTest.main(ThrowTest.java:12)
原理:但抛出异常后将使用使用new在堆上创建异常对象,然后你的执行路径被终止,并且从当前环境中弹出对异常对象的引用,此时异常处理机制接管程序,并开始找一个恰当的地方执行程序,这个恰当的地方就是异常处理程序,它的任务就是将程序从错误状态中恢复。
public static void main(String[] args) {
testThrows(args);
}
public static void testThrows(String[] tmp) {
try {
createThrows(tmp);
} catch (Exception e) {
// TODO: handle exception
System.out.println("come from createThrows ");
}
}
public static void test2Throws(String[] tmp) throws Exception {
createThrows(tmp);
}
public static void createThrows(String[] tmp){
int num = 0;
num = Integer.parseInt(tmp[0]);
System.out.println("你输入的数字为:"+num);
}
throws和throw可以组合在一起使用,就是在捕获异常后抛出一个明确的异常个调用者。
二者的区别:
throw是用在方法中的,throws是用在方法签名之后的,在同一个地方使用这些的时候要注意,throws抛出异常的类型范围要比throw的大才行。
public static void main(String[] args) {
try {
methodA();
} catch(Exception e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
methodB();
}
public static void methodA() {
try {
System.out.println("come in A");
throw new RuntimeException("制造异常");
} finally {
// TODO: handle exception
System.out.println("用A的finally ");
}
}
public static void methodB() {
try {
System.out.println("come in B");
return; //这里返回,在执行完finally语句后才返回
} finally {
// TODO: handle exception
System.out.println("用B的finally ");
}
}
结果:
come in A
用A的finally
制造异常
come in B
用B的finally
3、getMessage和printStackTrace方法
getMessage:返回此throwable对象的详细消息字符串
printStackTrace:将此throwable对象及其追踪输出至标准错误流
try{
fun();
}catch(Exception e){
e.getMessage(e);
// e.printStackTrace(e);
}
三、自定义异常类
一般都选择Exception作为父类,如下:
public class MyException extends Exception{
public MyException(){
super();
}
public MyException(String msg){
super(msg);
}
public MyException(Throwable cause){
super(cause);
}
public MyException(String msg,Throwable cause){
super(msg, cause);
}
}
其实并不是所有的异常都需要处理,异常处理会占用一定的资源,影响程序的执行效率。认真观察异常的名字和行号,尽量减少try语句块的体积,在处理异常的时候应该打印出该异常的堆栈信息以方便调试使用。
对异常对象的清理并不需要过多的关心,因为他们都是用new在堆上建立的,垃圾回收器会自动将他们清理掉。