1.异常处理不能代替简单的测试
例:试着上百万次地对一个空栈进行退栈操作。在实施退栈操作之前,首先要查看栈是否为空。
if(!s.empty()) s.pop();
接下来,强行进行退栈操作。然后,捕获EmptyStackException异常来告知我们不能这样做:
try
{
s.pop();
}
catch(EmptyStackException e)
{
}
在测试的机器上,调用isEmpty的版本运行时间为646毫秒。捕获EmptyStackException的版本运行时间为21739毫秒。 可以看出,与执行简单的测试相比,捕获异常花费的时间大大超过了前者,因此使用异常的基本规则是:只在异常情况下使用异常机制。
2.不要过分地细化异常
有必要将整个任务包装在一个try语句块中,这样,当任何一个操作出现问题时,整个任务都可以取消
try
{
for(i=0;i<100;i++)
{
n=s.pop();
out.writeInt(n);
}
}
catch(IOException e)
{
//problem writting to file
}
catch(EmptyStackException e)
{
//stack was empty
}
这段代码看起来清晰多了。这样也满足了异常处理机制的其中一个目标,将正常处理与错误处理分开。
3.利用异常层次结构
不要只抛出RuntimeException异常、应该寻找更加适当的子类或创建自己的异常类。
不要只捕获Throwable异常,否则,会使程序代码更难读、更难维护。
考虑受查异常与非受查异常的区别。已检查异常本来就很庞大,不要为逻辑错误抛出这些异常。
将一种异常转换成另一种更加适合的异常时不要犹豫,如:在解析某个文件中的一个整数时,捕获NumberFormatException异常,然后将它转换成IOException或MySubsystemException的子类。
4.不要压制异常
在Java中,更倾向关闭异常。如果编写了一个调用另一个方法的方法,而这个方法有可能100年才抛出一个异常,那么,编译器会因为没有将这个异常列在throws表中产生抱怨。而没有将这个异常列在throws表中主要出于编译器将会对所有调用这个方法的方法进行异常处理的考虑。因此,应该将这个异常关闭:
public Image loadImage(String s)
{
try
{
//code that threatens to throw checked exceptions
}
catch (Exception e)
{} //so here
}
现在即使发生异常也会被忽略