我有一个这样的循环:

for (int i = 0; i < max; i++) {
    String myString = ...;
    float myNum = Float.parseFloat(myString);
    myFloats[i] = myNum;
}

这是一个方法的主要内容,该方法的唯一目的是返回浮点数数组。我想让这个方法在出现错误时返回null,所以我把循环放在try…Catch block,像这样:

try {
    for (int i = 0; i < max; i++) {
        String myString = ...;
        float myNum = Float.parseFloat(myString);
        myFloats[i] = myNum;
    }
} catch (NumberFormatException ex) {
    return null;
}

但后来我也想到试一试……Catch块在循环中,像这样:

for (int i = 0; i < max; i++) {
    String myString = ...;
    try {
        float myNum = Float.parseFloat(myString);
    } catch (NumberFormatException ex) {
        return null;
    }
    myFloats[i] = myNum;
}

是否有任何理由,性能或其他方面,更喜欢其中一个?


编辑:共识似乎是,将循环放在try/catch中更干净,可能是在它自己的方法中。然而,关于哪个速度更快仍存在争议。有人能测试一下并给出一个统一的答案吗?


当前回答

虽然性能可能是相同的,“看起来”更好的是非常主观的,但在功能上仍然有相当大的差异。举个例子:

Integer j = 0;
    try {
        while (true) {
            ++j;

            if (j == 20) { throw new Exception(); }
            if (j%4 == 0) { System.out.println(j); }
            if (j == 40) { break; }
        }
    } catch (Exception e) {
        System.out.println("in catch block");
    }

while循环位于try catch块内,变量'j'将递增到40,当j mod 4为零时输出,当j达到20时抛出异常。

在详细介绍之前,先来看另一个例子:

Integer i = 0;
    while (true) {
        try {
            ++i;

            if (i == 20) { throw new Exception(); }
            if (i%4 == 0) { System.out.println(i); }
            if (i == 40) { break; }

        } catch (Exception e) { System.out.println("in catch block"); }
    }

与上面的逻辑相同,唯一不同的是try/catch块现在在while循环中。

下面是输出(在try/catch中):

4
8
12 
16
in catch block

而另一个输出(try/catch in while):

4
8
12
16
in catch block
24
28
32
36
40

这里有很大的不同:

While in try/catch跳出循环

Try /catch in while保持循环活动

其他回答

为try/catch设置一个特殊的堆栈框架会增加额外的开销,但是JVM可能能够检测到您正在返回并优化它。

根据迭代次数的不同,性能差异可能可以忽略不计。

然而,我同意其他人的观点,把它放在循环之外会让循环体看起来更干净。

如果您希望继续处理,而不是在存在无效数字时退出,那么您将希望代码位于循环中。

如果将try/catch放在循环中,则会在异常发生后继续循环。如果你把它放在循环之外,你会在抛出异常时立即停止。

异常的全部意义在于鼓励第一种风格:让错误处理被合并并处理一次,而不是在每个可能的错误位置立即处理。

如果它在内部,那么您将获得N次try/catch结构的开销,而不是只在外部获得一次。


每次调用Try/Catch结构都会增加方法执行的开销。只需要处理结构所需的一点点内存和处理器节拍。如果运行一个循环100次,假设每个try/catch调用的代价是1 tick,那么在循环内执行try/catch调用的代价是100 tick,而在循环外只执行1 tick。

As already mentioned, the performance is the same. However, user experience isn't necessarily identical. In the first case, you'll fail fast (i.e. after the first error), however if you put the try/catch block inside the loop, you can capture all the errors that would be created for a given call to the method. When parsing an array of values from strings where you expect some formatting errors, there are definitely cases where you'd like to be able to present all the errors to the user so that they don't need to try and fix them one by one.