异常处理:
代码不佳的代码不能运行
特例
RuntimeException
在Java程序中,Java提供了标准的运行时代码检测。就像传递给方法的每个引用都检查其是否为null,如果对null引用进行调用,Java会自动抛出NullPointerException异常,所以不必这样:
if(t != null){
// 无谓的嵌套判断
t.toString();
...
}
if(t == null){
// 无谓的嵌套判断
throw new RuntimeException();
}
// 可以这样
if(t == null){
t = new String();
...
}
尽管你也许想要执行其他的检查以确保NullPointerException不会出现。
属于运行时的异常的类型有很多,它们会自动被Java虚拟机抛出,所以不必在异常说明中把它们列出来。
所以请务必记住:只能在代码中忽略RuntimeException(及其子类)类型的异常,其他类型异常的处理都是由编译器强制实施的。原因是RuntimeException代表的是编程错误:可能是无法预料的错误,也可能是代码编写漏洞。
构造器
构造器创建对象也可能会失败,那就会触发异常机制,但是还有一点,有些时候要手动关闭打开的对象:如文件对象。
Java的缺陷:出了内存的清理之外,所有的清理都不会自动发生。所以这就要求程序员去手动编写好代码才行。
// 一个文件输入的正确例子
public class Cleanup{
public static void main(String [] args){
try {
InputFile in = new InputFile("Cleanup.java");
try {
String s ;
int i = 1;
while((s = in.getLine()) != null){
// Perform line-by-line processing here...
}
} catch(Exception e){
System.out.println("Caught Exception in main");
e.printStackTrace(System.out);
} finally {
in.dispose();
}
} catch(Exception e) {
System.out.println("InputFile construction failed");
}
}
}
Output: dispose() successful
这也就是要求我们在可去除对象后面紧跟try-finally的原则。
另外异常捕获还有重要的一条原则,那就是:
只有在你知道如何处理异常的情况下才捕获异常
异常使用指南
- 在恰当的级别处理问题。(即在指导如何处理的情况下才捕获异常)
- 解决问题并且重新调用产生异常的方法。
- 进行少许修补,然后绕过异常发生的地方继续执行。
- 用别的数据进行计算,以代替方法预计会返回的值。
- 把当前运行环境下能做的事情尽量做完,然后把相同的异常重抛到更高层。
- 把当前运行环境下能做的事情尽量做完,然后把不同的异常抛到更高层。
- 终止程序。
- 进行简化。(如果你的异常模式使问题变得太复杂,那用起来会非常痛苦也很烦人)
- 让类库和程序更安全。(这既是在为调试做短期投资,也是为程序的健壮性做长期投资。)