我有一个这样的循环:

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中更干净,可能是在它自己的方法中。然而,关于哪个速度更快仍存在争议。有人能测试一下并给出一个统一的答案吗?


当前回答

在你的例子中没有功能上的区别。我觉得你的第一个例子可读性更强。

其他回答

上面没有提到的另一个方面是,每个try-catch都会对堆栈产生一些影响,这可能会对递归方法产生影响。

如果方法"outer()"调用方法"inner()"(它可能递归地调用自己),如果可能的话,尝试在方法"outer()"中找到try-catch。我们在性能类中使用的一个简单的“堆栈崩溃”示例,当try-catch在内部方法中时,在大约6400帧时失败,当它在外部方法中时,在大约11,600帧时失败。

在现实世界中,如果您正在使用Composite模式并且具有大型、复杂的嵌套结构,这可能会成为一个问题。

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

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

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

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

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

把它放在里面。您可以继续处理(如果您愿意),也可以抛出一个有用的异常,告诉客户端myString的值和包含坏值的数组的索引。我认为NumberFormatException已经告诉您坏的值,但原则是将所有有用的数据放在您抛出的异常中。考虑一下在程序的调试器中,您会对什么感兴趣。

考虑:

try {
   // parse
} catch (NumberFormatException nfe){
   throw new RuntimeException("Could not parse as a Float: [" + myString + 
                              "] found at index: " + i, nfe);
} 

在需要的时候,您将非常感谢这样一个异常,其中包含尽可能多的信息。

性能:就像Jeffrey在他的回复中所说的,在Java中这并没有太大的区别。

通常,为了代码的可读性,在哪里捕获异常的选择取决于您是否希望循环继续处理。

在您的示例中,您在捕获异常时返回。在这种情况下,我会在循环中放入try/catch。如果你只是想捕捉一个坏值,但继续处理,把它放在里面。

第三种方法:您总是可以编写自己的静态ParseFloat方法,并在该方法中而不是在循环中处理异常处理。使异常处理与循环本身隔离!

class Parsing
{
    public static Float MyParseFloat(string inputValue)
    {
        try
        {
            return Float.parseFloat(inputValue);
        }
        catch ( NumberFormatException e )
        {
            return null;
        }
    }

    // ....  your code
    for(int i = 0; i < max; i++) 
    {
        String myString = ...;
        Float myNum = Parsing.MyParseFloat(myString);
        if ( myNum == null ) return;
        myFloats[i] = (float) myNum;
    }
}