Java异常结构:
Error :称为错误,由Java虚拟机生成并抛出,包括动态链接失败。虚拟机错误等,程序不对其做处理。
Exception :所有异常类的父类,其子类对应了各种各样可能出现的异常事件,一般需要用户显示地声明或
者捕获。
Runtime Exception :一类特殊的异常,如被0除。数组下标超出范围等,其产生比较频繁,处理麻烦,如果
显示地声明或捕获将对程勋可读性和运行效率影响很大。因此由系统自动检测并将它们交给缺省的异常处
理程序(用户可不比对其处理,不必去CATCH)。
Try - catch - finally:
try {
throw new TestException();
} catch (TestException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
clean();
}
-
必须先catch较小的异常,在catch大的
-
Finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序的其他部分以前,能够对程序的状态作统一的管理.
-
无论try所指定的程序块中是否抛出列外,finally所指定的代码都要被执行。
-
通常在finally语句中可以进行资源的清除工作,如:关闭打开的文件,删除临时文件 (finally 中重新抛出另外的异常 or return ,异常会丢失)
重新抛出异常
重抛异常会把异常抛给上一级环境中的异常处理程序,同一个try块的后续catch子句将被忽略
此外,异常对象的所有信息多得以保留,所以printStackTrace()方法将是原来异常抛出点的调用栈的信息,而非重新抛出点的信息,要更新这个信息,调用fillINStackTrace()方法
public class Rethrowing {
public static void f() throws Exception {
System.out.println("originating the exception in f()");
throw new Exception("thrown from f()");
}
public static void g() throws Exception {
try {
f();
} catch(Exception e) {
System.out.println("Inside g(),e.printStackTrace()");
e.printStackTrace(System.out);
throw e;
}
}
public static void h() throws Exception {
try {
f();
} catch(Exception e) {
System.out.println("Inside h(),e.printStackTrace()");
e.printStackTrace(System.out);
throw (Exception)e.fillInStackTrace();
}
}
public static void main(String[] args) {
try {
g();
} catch(Exception e) {
System.out.println("main: printStackTrace()");
e.printStackTrace(System.out);
}
try {
h();
} catch(Exception e) {
System.out.println("main: printStackTrace()");
e.printStackTrace(System.out);
}
}
} /* Output:
originating the exception in f()
Inside g(),e.printStackTrace()
java.lang.Exception: thrown from f()
at Rethrowing.f(Rethrowing.java:7)
at Rethrowing.g(Rethrowing.java:11)
at Rethrowing.main(Rethrowing.java:29)
main: printStackTrace()
java.lang.Exception: thrown from f()
at Rethrowing.f(Rethrowing.java:7)
at Rethrowing.g(Rethrowing.java:11)
at Rethrowing.main(Rethrowing.java:29)
originating the exception in f()
Inside h(),e.printStackTrace()
java.lang.Exception: thrown from f()
at Rethrowing.f(Rethrowing.java:7)
at Rethrowing.h(Rethrowing.java:20)
at Rethrowing.main(Rethrowing.java:35)
main: printStackTrace()
java.lang.Exception: thrown from f()
at Rethrowing.h(Rethrowing.java:24)
at Rethrowing.main(Rethrowing.java:35)
*///:~
异常链
在捕获一个异常后抛出另外一个异常,并且保留原始异常的信息,
除了Error,Exception,RuntimeException,其他类型的异常要连接起来,应该使用initCause()
public Object setField(String id, Object value)
throws DynamicFieldsException {
if(value == null) {
// Most exceptions don't have a "cause" constructor.
// In these cases you must use initCause(),
// available in all Throwable subclasses.
DynamicFieldsException dfe =
new DynamicFieldsException();
dfe.initCause(new NullPointerException());
throw dfe;
}
异常的限制
package com.lwf.thinking.eight;
class BaseBallException extends Exception{}
class Foul extends BaseBallException{}
class Strike extends BaseBallException{}
abstract class Inning{
public Inning() throws BaseBallException{}
//注意构造方法抛出了异常。
public void event() throws BaseBallException{
//这里并没有显式throw new BaseBallException();
}
public abstract void getName() throws Foul,Strike;
public void getAge(){}
}
class StormException extends Exception{}
class RainedOut extends StormException{}
class PopFoul extends Foul{}
interface Storm{
public void event() throws RainedOut;
public void rainHard() throws RainedOut;
}
public class UserDefineException extends Inning implements Storm{
public UserDefineException() throws BaseBallException,RainedOut{
//1、因为基类的构造方法抛出了异常,根据继承机制,实例化该类必然调用基类实例化,所以该类的构造方法必须显式抛出异常
//2、派生类的构造方法可以抛出基类所没有抛出的异常如RainedOut,注意这一点非构造方法不行。
}
public UserDefineException(String s) throws BaseBallException,PopFoul{}//只要抛出类型包含了BaseBallException即可,类国基类只抛出此类型
// public void getName() throws Foul, Strike{}
//3、派生类抛出与基类所抛出的对应异常。
// public void getName() throws Foul{}
// public void getName() throws Strike{}
//4、仅抛出与基类该方法抛出异常中的任意一个
public void getName() throws PopFoul{ }
//5、上例中抛出了从Foul继承而来的PopFoul异常
// public void getName(){}
//6、不抛出任何对应异常
// public void getName() throws BaseBallException{}
//7、compile error,抛出了不与基类对应的抛出异常,注意这里BaseBallException是Strike和Foul的父类也是不行的。
public void event(){}
//子类可以不抛出父类的任何异常。
//! public void event()throw RainedOut{}
//interface cannot add exceptions to existing methods
// from the base class
//注意两个基类抛出了不同的异常:这时即使用public void event() throws BaseBallException, RainedOut{}也是不行的。
public void rainHard() throws RainedOut{}
public static void main(String[] args){
try {
UserDefineException u = new UserDefineException();
u.getName();
} catch (PopFoul e){
System.out.println("PopFoul");
} catch (RainedOut e) {
System.out.println("RainedOut");
} catch (BaseBallException e) {
System.out.println("BaseBallException");
}
try {
Inning i = new UserDefineException();
i.getName();
//向上转型才要求捕获基类所抛出异常,如果不进行向上转型是可以不要求捕获的。
} catch (RainedOut e) {
System.out.println("RainedOut");
} catch (Foul e) {
System.out.println("BaseBallException");
} catch (Strike e) {
e.printStackTrace();
} catch (BaseBallException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
总结一下关于异常的限制:
-
对构造方法:基类构造方法抛出异常,派生类构造方法必须显式抛出对应异常(如上例第1点),且可以抛出其它异常,(如上例第2点)
实质上来说异常限制对构造器不起作用,即构造器可抛出任何异常,但因为派生类构造器不能捕获基类构造器抛出的异常,所以派生类所抛出异常中必须要包含基类所抛出的异常。 ( http://wen66.iteye.com/blog/828820) -
对普通方法:基类普通方法抛出异常,派生类普通方法可抛出对应异常(如上例第3点)、可少抛出异常(如上例第4点)、
可抛出对应基类异常的继承异常子类(如上例第5点)、也可不抛出异常(如上例第6点),但不能抛出与基类不对应的异常(如上例第7点) -
特殊情况: 上例中的event方法,因为基类和接口都有event方法,并且抛出的异常类型又不相同,那么注意的是派生这里只有选择不抛出异常,因为
不管抛出哪一个或是抛出两个都是不行的。 -
异常说明:
异常说明本身并不属于方法原型的一部分,所以不能根据异常说明的不同来重载方法。
一个出现在基类异常说明中的异常,不一定会出现在派生类的异常说明中。这点与继承的规则是不同的。
project
web.xml
</session-config>
<error-page>
<exception-type>com.geenergy.pmt.exception.PMTSessionExpirationException</exception-type>
<location>/jsp/extra/sessiontimeout.jsp</location>
</error-page>