第十二章 通过异常处理错误

[color=blue]异常参数[/color]

throw new NullPointerException("t = null");

关键字throw将触发许多十分奇妙的事情。通常,你首先使用new来创建对象,用以表示错误情况,此对象的引用将传给throw。尽管返回的异常对象其类型通常与方法设计的返回类型不同,但从效果上看,它就像是从方法“返回”的。
此外,你能抛出任意类型的Throwable(它是异常类型的根类)对象。

[color=blue]栈轨迹[/color]
public class WhoCalled {
static void f() {
try {
throw new Exception();
} catch (Exception e) {
for (StackTraceElement ste : e.getStackTrace()) {
System.out.println(ste.getMethodName());
}
}
}
static void g() {
f();
}
static void h() {
g();
}
public static void main(String[] args) {
f();
System.out.println("--------------------------");
g();
System.out.println("--------------------------");
h();
}
}
Output :
f
main
--------------------------
f
g
main
--------------------------
f
g
h
main


[color=blue]重新抛出异常[/color]

如果你只是把当前异常对象重新抛出,那么printStackTrace( )方法显示的将是原来异常抛出点的调用栈信息,而并非重新抛出点的信息。要想更新这个信息,你可以调用fillInStackTrace( )方法,这将返回一个Throwable对象,它是通过把当前调用栈信息填入原来那个异常对象而建立的。

你有可能会在捕获异常之后抛出另一种异常。这么做的话,将得到类似使用fillInStackTrace( )的效果,有关原来异常发生地点的信息会丢失,剩下的是与新的抛出地点有关的信息:

最后那个异常仅知道自己来自main(),而对f()一无所知。

你永远不用为清理前一个异常对象而担心,或者说为异常对象的清理担心。它们都是用new在堆上创建的对象,所以垃圾回收器会自动把它们清理掉。

[color=blue]java标准异常[/color]

所以Java程序员关心的主要是Exception。
异常的基本的概念是用名称代表发生的问题,并且异常的名称应该可以望文知意。

[color=blue]特例RuntimeException[/color]

属于运行期异常的类型有很多。它们会自动被Java虚拟机抛出,所以你不必在异常说明中把它们列出来。这些异常都是从RuntimeException类继承而来,所以既体现了继承的优点,使用起来也很方便。
RuntimeException类型的异常也许会穿越所有的执行路径直达main( )方法,而不会被捕获。要明白到底发生了什么,可以试试下面的例子:
import com.bruceeckel.simpletest.*; 
public class NeverCaught {
private static Test monitor = new Test();
static void f() {
throw new RuntimeException("From f()");
}
static void g() {
f();
}
public static void main(String[] args) {
g();
monitor.expect(new String[] {
"Exception in thread \"main\" " +
"java.lang.RuntimeException: From f()",
" at NeverCaught.f(NeverCaught.java:7)",
" at NeverCaught.g(NeverCaught.java:10)",
" at NeverCaught.main(NeverCaught.java:13)"
});
}
} ///:~

所以答案是:如果RuntimeException没有被捕获而直达main( ),那么在程序退出前将调用异常的printStackTrace( )方法。

[color=red]请务必记住:你只能在代码中忽略RuntimeException(及其子类)类型的异常,其它类型异常的处理都是由编译器强制实施的。究其原因,RuntimeException代表的是编程错误:[/color]

1.你无法预料的错误。比如从你控制范围之外传递进来的null引用。
2.作为程序员,你应该在代码中进行检查的错误。(比如对于ArrayIndexOutOfBoundsException,你就得注意一下数组的大小了。)在一个地方发生的异常,常常会在另一个地方导致错误。

[color=blue]异常的限制[/color]

[color=red]当你重载方法的时候,你只能抛出在父类方法的异常说明里列出的那些异常。[/color]这个限制很有用,因为这样的话,对父类能工作的代码应用到子类对象的时候,一样能够工作(当然,这是面向对象的基本概念),异常也不例外。
异常限制对构造器不起作用。派生类构造器的异常说明必须包含基类构造器的异常说明。注意,派生类构造器不能捕获基类构造器抛出的异常。

[color=red]异常使用指南[/color]

你应该在下列情况下使用异常:

1.在恰当的级别处理问题。(在你知道该如何处理的情况下才捕获异常)。
2.解决问题并且重新调用产生异常的方法。
3.进行少许修补,然后绕过异常发生的地方继续执行。
4.用别的数据进行计算,以代替方法返回的期望值。
5.把当前运行环境下能做的事情尽量作完,然后把相同的异常重抛(rethrow)到更高层。
6.把当前运行环境下能做的事情尽量作完,然后把不同的异常抛(throw)到更高层。
7.终止程序。
8.进行简化。(如果异常把问题搞得太复杂,那用起来会非常痛苦也很烦人。)
9.让类库和程序更安全。(这既是在为调试做短期投资,也是在为程序的健壮性做长期投资。)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值