Java:异常作为控制流?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1546514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 17:02:19  来源:igfitidea点击:

Java: Exceptions as control flow?

javaexceptioncontrol-flow

提问by Nick Heiner

I've heard that using exceptions for control flow is bad practice. What do you think of this?

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

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
        }

So, if no match has been found, the ints will be -1. This will cause an exception when I try to take the substring g0.substring(0, -1). Then the function just returns an object indicating that no match is found.

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

Is this bad practice? I could just check each index manually to see if they're all -1, but that feels like more work.

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

UPDATE

更新

I have removed the try-catch block and replaced it with this:

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

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

Which is better: checking if each variable is -1, or using a boolean foundMatchto keep track and just check that at the end?

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

回答by Yannick Motton

Generally exceptions are expensive operations and as the name would suggest, exceptional conditions. So using them in the context of controlling the flow of your application is indeed considered bad practice.

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

Specifically in the example you provided, you would need to do some basic validation of the inputs you are providing to the StringMatch constructor. If it were a method that returns an error code in case some basic parameter validation fails you could avoid checking beforehand, but this is not the case.

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

回答by Kevin Day

I've done some testing on this. On modern JVMs, it actually doesn't impact runtime performance much (if at all). If you run with debugging turned on, then it does slow things down considerably.

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

See the following for details

详情请看以下内容

(I should also mention that I still think this is a bad practice, even if it doesn't impact performance. More than anything, it reflects a possibly poor algorithm design that is going to be difficult to test)

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

回答by Scott Taylor

Program flow should be in as straight a line as possible(since even thenapplications get pretty complex), and utilize standard control flow structures. The next developer to touch the code may not be you and (rightly)misunderstand the non-standard way you are using exceptions instead of conditionals to determine control flow.

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

I am fighting a slightly different slant on this problem right now during some legacy code refactoring.

在一些遗留代码重构期间,我现在正在与这个问题略有不同的倾向。

The largest issue that I find with this approach is that using the try/catch breaks normal programmatic flow.

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

In the application I am working on(and this is different from the sample you have applied), exceptions are used to communicate from within a method call that a given outcome(for instance looking for an account number and not finding it) occurred. This creates spaghetti code on the client side, since the calling method (during a non-exceptional event, or a normal use-case event) breaks out of whatever code it was executing before the call and into the catch block. This is repeated in some very long methods many times over, making the code very easy to mis-read.

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

For my situation, a method should return a value per it's signature for all but truly exceptional events. The exception handling mechanism is intended to take another path when the exception occurs (try and recover from within the method so you can still return normally).

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

To my mind you could do this if you scope your try/catch blocks verytightly; but I think it is a bad habit and can lead to code that is very easy to misinterpret, since the calling code will interpret any thrown exception as a 'GOTO'type message, altering program flow. I fear that although this case does not fall into this trap, doing this often could result in a coding habit leading to the nightmare that I am living right now.

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

And that nightmare is not pleasant.

那个噩梦并不愉快。

回答by SingleShot

Yes, this is a bad practice, especially when you have a means to avoid an exception (check the string length before trying to index into it). Try and catch blocks are designed to partition "normal" logic from "exceptional" and error logic. In your example, you have spread "normal" logic into the exceptional/error block (not finding a match is not exceptional). You are also misusing substringso you can leverage the error it produces as control flow.

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