我有一个看起来像这样的循环:
for (int i = 0; i < max; i++) { String myString = ...; float myNum = Float.parseFloat(myString); myFloats[i] = myNum; }
这是唯一目的是返回浮点数组的方法的主要内容。null如果出现错误,我希望此方法返回,因此我将循环放在一个try...catch块中,如下所示:
null
try...catch
try { for (int i = 0; i < max; i++) { String myString = ...; float myNum = Float.parseFloat(myString); myFloats[i] = myNum; } } catch (NumberFormatException ex) { return null; }
但是后来我也想到了将try...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 中更干净,可能放在它自己的方法中。但是,仍然存在关于哪个更快的争论。有人可以对此进行测试并给出统一的答案吗?
好吧,在Jeffrey L Whitledge 说没有性能差异(截至 1997年)之后,我去测试了它。我运行了这个小基准测试:
public class Main { private static final int NUM_TESTS = 100; private static int ITERATIONS = 1000000; // time counters private static long inTime = 0L; private static long aroundTime = 0L; public static void main(String[] args) { for (int i = 0; i < NUM_TESTS; i++) { test(); ITERATIONS += 1; // so the tests don't always return the same number } System.out.println("Inside loop: " + (inTime/1000000.0) + " ms."); System.out.println("Around loop: " + (aroundTime/1000000.0) + " ms."); } public static void test() { aroundTime += testAround(); inTime += testIn(); } public static long testIn() { long start = System.nanoTime(); Integer i = tryInLoop(); long ret = System.nanoTime() - start; System.out.println(i); // don't optimize it away return ret; } public static long testAround() { long start = System.nanoTime(); Integer i = tryAroundLoop(); long ret = System.nanoTime() - start; System.out.println(i); // don't optimize it away return ret; } public static Integer tryInLoop() { int count = 0; for (int i = 0; i < ITERATIONS; i++) { try { count = Integer.parseInt(Integer.toString(count)) + 1; } catch (NumberFormatException ex) { return null; } } return count; } public static Integer tryAroundLoop() { int count = 0; try { for (int i = 0; i < ITERATIONS; i++) { count = Integer.parseInt(Integer.toString(count)) + 1; } return count; } catch (NumberFormatException ex) { return null; } } }
我使用 javap 检查了生成的字节码,以确保没有内联。
结果表明,假设 JIT 优化不显着, Jeffrey 是正确的 ; Java 6、Sun 客户端 VM 上 绝对没有性能差异(我无法访问其他版本)。在整个测试中,总时间差大约为几毫秒。
因此,唯一的考虑是看起来最干净的东西。我发现第二种方式很难看,所以我会坚持第一种方式或Ray Hayes的方式。
性能:在 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; } }