【java基础(四十九)】异常(五)使用异常机制的技巧

目前,存在着大量有关如何恰当地使用异常机制的争论。有些程序员认为所有的已检查异常都很令人厌恶;还有一些程序员认为能够抛出的异常量不够。我们认为异常机制有其用武之地。下面给出使用异常机制的几个技巧。

异常处理不能代替简单的测试

作为一个示例,在这里编写一段代码,试着上百次地对一个空栈进行退栈操作。在实施退栈操作之前,首先要看栈是否为空。

if (!s.empty()) s.pop();

接下来,强行进行退栈操作。然后,捕获EmptyStrackException异常来告知我们不能这样做:

try {
	s.pop();
} catch (EmptyStractException e) {

}

与执行简单的测试相比,捕获异常所花费的时间大大超过了前者。因此使用异常的基本规则是:只在异常情况下使用异常机制。

不要过分地细化异常

很多程序员习惯将每一条语句都分装在一个独立的try语句块中。

PrintStream out;
Strack s;
for (int i = 0; i < 100; i++) {
	try {
		n = s.pop();
	} catch (EmptyStrackException e) {
		...
	}
	try {
		out.writeInt(n);
	} catch (IOException e) {
		...
	}
}

这种编程方式将导致代码量的急剧膨胀。首先看一下这段代码所完成的任务。在这里,希望从栈中弹出100个数值,然后将它们存入一个文件中。如果栈是空的,则不会变成非空状态;如果文件出现错误,则也很难给予排除。如果出现上述问题后,这种编程方式无能为力。因此,有必要将整个任务包装在一个try语句块中,这样,在任何一个操作出现问题时,整个任务都可以取消。

try {
	for (i = 0; i < 100; i++) {
		n = s.pop();
		out.writeInt(n);
	}
} catch (IOException e) {
	...
} catch (EmptyStrackException e) {
	...
}

这段代码看起来清晰多了。这样也满足了异常处理机制的其中一个目标,将正常处理与错误处理分开。

利用异常层次结构

不要只抛出RuntimeException异常。应该寻找更加适当的子类或创建自己的异常类。

不要只捕获Throwable异常,否则,会使程序代码更难度、更难维护。

考虑受查异常和非受查异常的区别。已检查异常本来就很庞大,不要为逻辑错误抛出这些异常。

将一种异常转换成另一种更适合的异常时不要犹豫。例如,在解析某个文件中的一个整数时,捕获NumberFormatException异常,然后将它转换成IOException或MySubsystemException的子类。

不要压制异常

在Java中,往往强烈地倾向关闭异常。如果编写了一个调用另一个方法的方法,而这个方法有可能100年才抛出一个异常,那么,编译器会因为没有将这个异常列在throws表中产生抱怨。而没有将这个异常列在throws表中主要出于编译器将会对所有调用这个方法的方法进行异常处理的考虑。因此,应该将这个异常关闭:

public void loadImage(String s) {
	try {
		...
	} catch (Exception e) {
		...
	}
}

现在,这段代码就可以通过编译了。除非发生异常,否则它将可以正常的运行。即使发生了异常也会被忽略。如果认为异常非常重要,就应该对它们进行处理。

在检测错误时,“苛刻”要比放任更好

当检测到错误的时候,有些程序员担心抛出异常。在用无效的参数调用一个方法时,返回一个虚拟的数值,还是抛出一个异常,哪种处理方式更好?例如,当栈空时,Strack.pop是返回一个null,还是抛出一个异常?我们认为:在出错的地方抛出一个EmptyStrackException异常要比在后面抛出一个NullPointerException异常要好。

不要羞于传递异常

很多程序员都感觉应该捕获抛出的全部异常。如果调用了一个抛出异常的方法,例如,FileInputStream构造器或readline方法,这些方法就会本能的捕获这些可能产生的异常。其实,传递异常要比捕获这些异常更好。

让高层次的方法通知用户发生了错误,或者放弃不成功的命令更加适宜。

捐赠

若你感觉读到这篇文章对你有启发,能引起你的思考。请不要吝啬你的钱包,你的任何打赏或者捐赠都是对我莫大的鼓励。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章