我有一个这样的循环:

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放在循环中,则会在异常发生后继续循环。如果你把它放在循环之外,你会在抛出异常时立即停止。

其他回答

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

我想添加我自己的0.02c,关于在哪里放置异常处理的一般问题时两个相互竞争的考虑因素:

The "wider" the responsibility of the try-catch block (i.e. outside the loop in your case) means that when changing the code at some later point, you may mistakenly add a line which is handled by your existing catch block; possibly unintentionally. In your case, this is less likely because you are explicitly catching a NumberFormatException The "narrower" the responsibility of the try-catch block, the more difficult refactoring becomes. Particularly when (as in your case) you are executing a "non-local" instruction from within the catch block (the return null statement).

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

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保持循环活动

我同意所有关于性能和可读性的帖子。然而,在某些情况下,这确实很重要。其他一些人也提到了这一点,但通过例子可能更容易理解。

考虑这个稍微修改过的例子:

public static void main(String[] args) {
    String[] myNumberStrings = new String[] {"1.2345", "asdf", "2.3456"};
    ArrayList asNumbers = parseAll(myNumberStrings);
}

public static ArrayList parseAll(String[] numberStrings){
    ArrayList myFloats = new ArrayList();

    for(int i = 0; i < numberStrings.length; i++){
        myFloats.add(new Float(numberStrings[i]));
    }
    return myFloats;
}

如果你想让parseAll()方法在有任何错误时返回null(就像原来的例子一样),你可以把try/catch放在外面,像这样:

public static ArrayList parseAll1(String[] numberStrings){
    ArrayList myFloats = new ArrayList();
    try{
        for(int i = 0; i < numberStrings.length; i++){
            myFloats.add(new Float(numberStrings[i]));
        }
    } catch (NumberFormatException nfe){
        //fail on any error
        return null;
    }
    return myFloats;
}

实际上,您可能应该在这里返回一个错误,而不是null,通常我不喜欢有多个返回,但您可以理解。

另一方面,如果你想让它忽略问题,并解析任何它能解析的字符串,你可以把try/catch放在循环的内部,像这样:

public static ArrayList parseAll2(String[] numberStrings){
    ArrayList myFloats = new ArrayList();

    for(int i = 0; i < numberStrings.length; i++){
        try{
            myFloats.add(new Float(numberStrings[i]));
        } catch (NumberFormatException nfe){
            //don't add just this one
        }
    }

    return myFloats;
}

这取决于故障处理。如果你只是想跳过error元素,请尝试内部:

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

在任何其他情况下,我宁愿到外面去试试。代码更可读,更干净。如果返回null,在错误情况下抛出一个IllegalArgumentException可能会更好。