13

我听说对控制流使用异常是不好的做法。你觉得这怎么样?

public static findStringMatch(g0, g1) {

    int g0Left = -1;
    int g0Right = -1;
    int g1Left = -1;
    int g1Right = -1;

//if a match is found, set the above ints to the proper indices
//...
//if not, the ints remain -1

        try {
            String gL0 = g0.substring(0, g0Left);
            String gL1 = g1.substring(0, g1Left);

            String g0match = g0.substring(g0Left, g0Right);
            String g1match = g1.substring(g1Left, g1Right);

            String gR0 = g0.substring(g0Right);
            String gR1 = g1.substring(g1Right);

            return new StringMatch(gL0, gR0, g0match, g1match, gL1, gR1);
        }
        catch (StringIndexOutOfBoundsException e) {
            return new StringMatch(); //no match found
        }

因此,如果未找到匹配项,则整数将为 -1。当我尝试获取 substring 时,这将导致异常g0.substring(0, -1)。然后该函数只返回一个表示未找到匹配项的对象。

这是不好的做法吗?我可以手动检查每个索引,看看它们是否都是-1,但这感觉像是更多的工作。

更新

我已经删除了 try-catch 块并将其替换为:

    if (g0Left == -1 || g0Right == -1 || g1Left == -1 || g1Right == -1) {
        return new StringMatch();
    }

哪个更好:检查每个变量是否为 -1,或者使用布尔值foundMatch来跟踪并在最后检查?

4

4 回答 4

19

通常,异常是昂贵的操作,顾名思义,异常情况。因此,在控制应用程序流的上下文中使用它们确实被认为是不好的做法。

特别是在您提供的示例中,您需要对提供给 StringMatch 构造函数的输入进行一些基本验证。如果它是在某些基本参数验证失败的情况下返回错误代码的方法,您可以避免事先检查,但事实并非如此。

于 2009-10-09T23:30:22.157 回答
10

我已经对此进行了一些测试。在现代 JVM 上,它实际上不会对运行时性能产生太大影响(如果有的话)。如果您在打开调试的情况下运行,那么它确实会大大减慢速度。

详情请参阅以下内容

(我还应该提到,我仍然认为这是一种不好的做法,即使它不会影响性能。最重要的是,它反映了可能难以测试的糟糕算法设计)

于 2009-10-10T00:13:17.873 回答
6

是的,这是一种不好的做法,尤其是当您有办法避免异常时(在尝试对其进行索引之前检查字符串长度)。Try 和 catch 块旨在将“正常”逻辑与“异常”和错误逻辑分开。在您的示例中,您已将“正常”逻辑传播到异常/错误块中(未找到匹配项并非异常)。您也在滥用substring,因此您可以利用它产生的错误作为控制流。

于 2009-10-10T00:10:14.553 回答
6

程序流应该尽可能直线(因为即使那样应用程序变得相当复杂),并使用标准控制流结构。下一个接触代码的开发人员可能不是您,并且(正确地)误解了您使用异常而不是条件来确定控制流的非标准方式。

在一些遗留代码重构期间,我现在在这个问题上的立场略有不同。

我发现这种方法的最大问题是使用 try/catch 会破坏正常的编程流程。

在我正在处理的应用程序中(这与您应用的示例不同),异常用于从方法调用中传达给定结果(例如查找帐号但未找到)发生。这会在客户端创建意大利面条式代码,因为调用方法(在非异常事件或正常用例事件期间)会中断它在调用之前执行的任何代码并进入 catch 块。这在一些非常长的方法中重复了很多次,使得代码很容易被误读。

对于我的情况,一个方法应该根据它的签名返回一个值,除了真正的异常事件。异常处理机制的目的是在异常发生时采取另一条路径(尝试从方法内恢复,以便您仍然可以正常返回)。

在我看来,如果您将 try/catch 块的范围非常严格,则可以这样做;但我认为这是一个坏习惯,可能导致代码很容易被误解,因为调用代码会将任何抛出的异常解释为“GOTO”类型的消息,从而改变程序流程。我担心虽然这个案例没有落入这个陷阱,但这样做通常会导致编码习惯导致我现在生活的噩梦。

而那个噩梦并不令人愉快。

于 2010-02-19T18:14:29.963 回答