9.5 异常处理规则

自作多情 提交于 2020-04-05 17:12:15


成功的异常处理应该实现如下4个目标
1、使程序代码混乱最小化
2、捕获并保留诊断信息
3、通知合适的人员
4、采用合适的方式结束异常活动

一、不要过度使用异常

过度使用异常主要有两个方面:
1、把异常和普通错误混淆在一起,不在编写任何错误处理代码,而是以简单地抛出异常来代替所有的错误处理。
2、使用异常处理代替流程控制。
对于完全已知的错误,应该编写处理这种错误的代码,增加程序的健壮性;对于普通错误,应该编写处理这种错误的代码,增加程序的健壮性。只有对于外部的、不能确定和预知的运行错误才使用异常。
比如五子棋游戏,处理用户输入坐标点已有棋子的两种方式:

//如果用户试图下棋的坐标点已有棋子
if(!gb.board[xpos-1][ypos-1].quales("+"))
{
    System.out.println("你输入的坐标点已有棋子了,请重新输入:");
    continue;
}

上面的处理方式检查用户试图下棋点已有棋子,立即打印一条提示语句,并重新开始下一次循环。这种处理方式简单明了,逻辑清晰。
如果将上面的机制改成如下方式:

//如果用户试图下棋的坐标点已有棋子,程序自行抛出异常
if(!gb.board[xpos-1][ypos-1].quales("+"))
{
    throw new Exception("你输入的坐标点已有棋子了");
}

上面的处理方式没有提供有效的错误处理代码,当程序检测到用户试图下棋点的坐标已经有棋子时,没有提供相应的处理,而是简单地抛出一个异常。这种方式虽然简单,但Java运行时接受到这个异常后,还需要进入相应的catch块来捕获该异常,所以运行效率要差一些。而且用户下棋重复这个错误完全是预料的,所以程序完全可以针对该错误提供相应的处理,而不是抛出异常。
必须指出:异常处理机制的初衷是将不可预期异常的处理代码和正常业务逻辑代码分离,因此绝不要使用异常处理来代替正常的业务逻辑判断。另外,异常机制效率比正常的流程控制效率差,所以不要使用异常处理来代替正常的程序流程控制。
例如下面代码:

    //定义一个字符串数组
    String[] arr={"Hello","Java","Spring"};
    //使用异常处理来遍历arr数组的每个元素
    try
    {
        var i=0;
        while(true)
        {
        System.out.println(arr[i++]);
        }
    }
    catch(ArrayIndexOutOfBoundsException ae)
    {}

上面这种代码可以实现遍历arr数组元素的功能,但这种写法的可读性较差,而且运行效率不高。程序完全有能力避免产生ArrayIndexOutOfBoundsException异常,程序“故意”制造这种异常,然后使用catch块去捕获该异常,这是不应该的。将程序改成如下形式好很多:

String[] arr={"Hello","Java","Spring"};
for(var i=0;i<arr.length;i++)
{
    System.out.println(arr[i]);
}

注意:异常应该只处理非正常情况,不要使用异常处理来代替正常的流程控制。对于一些完全可预知,而且处理方式清除的错误,程序应该提供相应的错误处理代码,而不是将其笼统地称为异常。

二、不要使用过于庞大的try块

在try块里的代码过于庞大,业务过于复杂,就会造成try块里出现异常的可能性大大增加,从而导致分析异常原因难度增大。
而且当try块过于庞大时,就难免在try块后紧跟大量的catch块才可以针对不同的异常提供不同的处理逻辑。同一个try块后紧跟大量的catch块则需要分析他们之间的逻辑关系,反而增加了编程难度。
正确的做法是,把大量的try块分割成多个可能出现的程序段落,并把它们单独放在try块中,从而分别捕获并处理异常。

三、避免使用Catch All语句

Catch All语句指的是一种异常捕获模块,它可以处理程序发生的所有可能异常。例如:

try 
{
    //可能引发Checked异常代码
}
catch (Throwable t)
{
    //进行异常处理代码
    t.printStackTrace();
}

在编写程序时应该避免使用这种异常处理方式,这种处理方式有两点不足:
1、所有异常都采用相同的处理方式,这将导致无法对不同的异常分情况处理,如果分情况处理,则需要在catch块中使用分支语句进行控制,这将是得不偿失的做法。
2、这种处理方式可能将程序中的错误、Runtime异常等可能导致程序终止的情况全部捕获到,从而“压制”了异常。如果出现了一些“关键”异常,那么此异常也会被“静悄悄”地忽略。

四、不要忽略捕获到的异常

既然捕获到异常,那catch块理应做些有用的事情——处理并修复这个错误。catch块整个为空,或者打印出错信息都是不妥的。
通常建议对异常采用适当的措施:
1、处理异常。对于异常进行合适的修复,然后绕过异常发生的地方继续执行;或用别的数据进行计算,以替代期望的方法的返回值;或者提示用户重写操作之.....总之对于Checked异常,程序应该尽量修复。
2、重新抛出新的异常。把当前运行环境下能做的事情尽量昨晚,然后进行异常转译,把异常包装成当前层的异常,重新抛出给上次调用者。
3、在合适的层处理异常。如果当前层不清楚如何处理异常,就不要在当前层使用catch语句来捕获异常,直接使用throws抛出该异常,让上次调用者来负责处理该异常。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!