1.创建异常类型
异常都是对象。所有的异常类型,即所有为可抛出(throwable)对象设计的类,都必须扩展Throwable或者它的某个子类。
异常主要是检查型异常(checked exception),这意味着编译器将检查我们的方法是否只抛出了它们声明自己会抛出的异常。标准运行时异常和错误扩展了RuntimeException或者Error,它们是不受检查型异常(unchecked exception)。
检查型异常表示的情形是:虽然这种情况是异常的,但是在一定程度上它的发生是可以预计的,而且一旦这种情况发生了,就必须以某种方式来处理。要使这种异常能够被检查到,必须表明这种异常的存在,并且要确保方法的调用者会以某种方式来处理异常,或者至少有意识地选择忽略它。
不受检查型异常表示的情形是:大体上说,它反映了我们程序逻辑中的错误,而且不能在运行时得到恢复。
要创建自己的异常类,必须从已有的异常类继承。几乎所有我们创建的异常都应该扩展自Exception,使它们成为检查型异常。
class MyException extends Exception{
}
public class InheritingExceptions {
public void method() throws MyException {
System.out.println("Throw MyException from method()");
throw new MyException();
}
public static void main(String[] args) {
InheritingExceptions ie = new InheritingExceptions();
try{
ie.method();
} catch(MyException me) {
System.out.println("Caught it!");
}
}
}
当抛出异常后,有几件事会随之发生。首先,将使用new在堆上创建异常对象。然后,当前执行路径被中止,这将导致调用链的逐级展开,其中的每一个调用都会中止,直至异常被捕获。如果异常没有被捕获,执行线程就会在给线程的UbcaughtExceptionHandler一次处理该异常的机会之后终止。
所有标准异常类都有两个构造器:一个是默认构造器;另一个是接受字符串参数,以便把相关信息放入异常对象的构造器。
2.异常捕获
如果在一个方法中抛出异常,你有两个选择:要么用catch子句捕获所有的异常,要么在方法声明中声明将要抛出的异常(throws)。可以通过try块包围代码来捕获异常。
try {
statements
} catch (exception_type1 identifier1) {
statements
} catch (exception_type2 identifier2) {
statements
} finally {
statements
}
其中,要么必须出现一个或多个catch子句,要么必须出现finally子句。try块会执行到有异常抛出或者顺利执行完毕。如果抛出了异常,每个catch子句按顺序从前到后检验该异常对象的类型是否可赋值给在catch子句中声明的类型。当找到一个可赋值的catch子句时,它的语句块被执行,同时其标识符会被设置为该异常对象的引用,任何其它的catch子句都不会再执行。finally的代码将在try内的所有其他处理都完成之后得到执行。如果try或者catch块内有return语句,finally语句在return之前执行。在finally语句中使用return语句将会使得try或者catch块中的return语句失效。
不要将捕获超类异常的catch子句放在捕获子类异常的catch子句的前面。由于catch子句是按顺序检查的,将造成第一个子句总是捕获异常,而后一个子句从来都不会执行。编译器不会接受下面的代码:
class SuperException extends Exception {
}
class SubException extends SuperException {
}
class BadCatch {
public void goodTry() {
try {
throw new SubException();
} catch(SuperException superRef) {
} catch(SubException subRef) {
}
}
}
3.栈轨迹
public class WhoCalled {
static void methodA() {
try {
throw new Exception();
} catch(Exception e) {
for(StackTraceElement ste : e.getStackTrace())
System.out.println(ste.getMethodName());
}
}
static void methodB() {
methodA();
}
static void methodC() {
methodB();
}
public static void main(String[] args) {
methodA();
System.out.println("----------------");
methodB();
System.out.println("----------------");
methodC();
}
}