通常情况对于程序来说,发现错误的理想时机是在编译阶段,运行程序之前。但是实际上在编译期很难找到所有的错误,大部分问题都是在运行期间找到并试图解决的。异常处理是JAVA中唯一正式的错误报告机制,通过编译期强制执行。
异常情形是指阻止当前方法或作用域继续执行问题。而普通问题指的是在当前环境下有足够多的信息能够处理这个错误。对于异常情形来说,在当前环境下没有足够多的信息去解决问题,我们只能从当前环境跳出,交由上一级环境去处理异常,这也就是抛出异常。
当抛出异常之后,首先,JAVA会同其他对象创建一样的流程,使用“new”在堆中创建异常对象;然后,程序当前的执行路径被终止,并从当前环境弹出对异常对象的引用;此时异常处理机制会接管此程序,并寻找一个恰当的地方执行程序。这个恰当的地方就是指异常处理程序,它的任务是将程序从错误状态中恢复使程序要么换一种方式运行,要么继续运行下去。
异常使我们可以将每件事当做一个事务来考虑,而异常可以看做是看护这些事务的底线。我们还可以将异常看做是一种內建的恢复系统,在我们的程序中可能拥有各种不同的恢复点,如果程序的某部分失败了,异常将恢复到程序的某个已知的稳定点上。
异常最重要的方面之一就是如果发生问题,将不允许程序沿着正常的路径走下去。异常允许我们强制程序停止允许,并告诉我们出现的问题,或者强制处理问题,返回到稳定态。
与JAVA中的其他对象一样,通过“new”在堆中创建异常对象时,也伴随着存储空间的分配和构建器的调用,所以标准异常类都有两个构建器:一个是默认构建器,另一个是接收字符串为参数,将相关信息放入异常对象的构建器。
关键字“throw”将产生许多有趣的结果,在创建了异常对象后,对象的引用传递给throw,尽管返回的异常对象类型通常与方法设计的返回类型不同,但从效果上来说,它就像是方法返回的,可以简单的把异常处理看做是一种不同的返回机制,另外还能用抛出异常的方式从当前的作用域内退出。
异常将在一个恰当的异常处理程序内得到解决,它的位置可能离异常抛出点很远,也可能跨越方法调用栈的许多层次。能够抛出任意类型的Throwable对象是异常类型的根类,对于不同类型的错误要抛出不同类型的异常,错误信息可以保存在异常对象内部或用异常类的名称暗示。
监控区域是一段可能产生异常的代码,并且后跟处理这些异常的代码。如果在方法内部抛出异常,或在方法内部调用的其他方法抛出了异常,这个方法将在抛出异常的过程中结束,在这个块中会尝试各种方法调用,所以叫做“try”块。有了异常处理机制,可以把所有的动作放入try块内,然后只需在一个地方就可以捕获这些异常。异常处理程序必须跟在try块之后,当异常被抛出后,异常处理机制将负责搜索参数与异常类型相匹配的第一个处理程序,然后进入catch语句执行,一旦catch语句结束,则处理程序的查找过程结束。
异常处理理论上有两种模型:
1.终止模型:在这种模型中,将假设错误非常关键,以至于程序无法返回到异常发生的地方继续执行,一旦异常被抛出,就表明错误已无法挽回,也不能回来继续执行。
2.恢复模型:在这种模型中,异常处理程序会修正错误,然后重新尝试调用出问题的方法,并认为第二次能够成功。对于恢复模型,通常希望异常被处理之后能够继续执行程序。如果要想用JAVA实现类似恢复的行为,那么在遇见错误时就不能抛出异常,而是调用方法来修正错误,或者把try块放入while循环中,不断进入try块,直到满意为止。
JAVA提供的异常体系不可能遇见所有的错误,我们通常需要自己定义异常类,并且需要从已有的异常类来继承。建立新的异常类型的最简单方法就是让编译器为我们产生默认的构建器,看下面一段代码:
package access;
class SimpleException extends Exception{}
public class InheritingExceptions {
public void f() throws SimpleException{
System.out.println("Throw SimpleException from f()");
throw new SimpleException();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
InheritingExceptions sed = new InheritingExceptions();
try{
sed.f();
}catch(SimpleException e){
System.out.println("Caught it !");
}
}
}
此程序的输出结果为:
也可以为异常类定义一个接收字符串参数的构建器,看下面一段代码:
package access;
class MyException extends Exception{
public MyException(){}
public MyException(String msg){ super(msg);}
}
public class FullConstructors {
public static void f() throws MyException{
System.out.println("Throwing MyException from f()");
throw new MyException();
}
public static void g() throws MyException{
System.out.println("Throwing MyException from g()");
throw new MyException("Originated in g()");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
try{
f();
}catch(MyException e){
e.printStackTrace(System.out);
}
try{
g();
}catch(MyException e){
e.printStackTrace(System.out);
}
}
}
此程序的输出结果为:
此例子调用了Throwable类中的printStackTrace方法,作用是打印从方法调用处到异常抛出处的方法调用序列。