尝试捕获比尝试资源更多或更少昂贵

时间:2015-01-28 16:17:34

标签: java exception-handling

问题

我刚刚开始重新使用Java,但从未有机会使用try-with-resources。从表面上看它看起来很棒,因为它可以减少代码,但是在幕后它是否比传统的try-catch或多或少昂贵的操作?我知道try-catch已经是一项昂贵的操作,因此我的好奇心。

我给这两种类型做了一个简单的测试,并没有发现任何差异:

测试实例

尝试资源测试

long startTime = System.currentTimeMillis();
ArrayList<String> list = null;

try (Scanner sc = new Scanner(new File("file.txt"))) {
    list = new ArrayList();
    while (sc.hasNext()) {
        list.add(sc.next());
    }
} catch (Exception ex) {
    System.err.println("Error: " + ex.getMessage());
} finally {
    long endTime = System.currentTimeMillis();
    System.out.println("The program completed in " + (endTime - startTime) + " ms");
}

传统的Try-Catch测试

long startTime = System.currentTimeMillis();
ArrayList<String> list = null;
Scanner sc = null;

try {
    sc = new Scanner(new File("file.txt"));
    list = new ArrayList();
    while (sc.hasNext()) {
        list.add(sc.next());
    }
} catch (Exception ex) {
    System.err.println("Error: " + ex.getMessage());
} finally {
    sc.close();
    long endTime = System.currentTimeMillis();
    System.out.println("The program completed in " + (endTime - startTime) + " ms");
}

结果

两者都产生了15-16ms的时间 - 完全没有明显的差异。但诚然,这是一个非常小的测试例子。

我的问题:引擎盖try-with-resources比传统try-catch更贵或更便宜?

4 个答案:

答案 0 :(得分:33)

  1. try-catch不是昂贵的部分。 抛出异常是(生成堆栈跟踪)。
  2. “昂贵”以上意味着“花费几微秒”。
  3. try-with-resources只是try-catch,具有可靠关闭资源所需的适当代码。
  4. 由于尝试在优化运行时(如HotSpot)中测量性能的所有众所周知的陷阱,您的测量代码无法证明任何事情。你需要热身,重复多次,等等。
  5. 如果您的结果超过10毫秒,那么显然您不会遇到try-catch问题,这可能会导致几微秒的开销。

答案 1 :(得分:10)

它的苹果和橘子。 ARM(自动资源管理或try-with-resources)块比您显示的旧式try-catch-finally块更有用。这是因为它生成的代码用于处理suppression mechanism.资源封闭中引发的异常(A related answer详细讨论了这一点。)

如果要编写新代码,请使用ARM块。它更易于阅读,维护,而且功能更多。除非您在严格受限的环境(如智能卡)中运行,否则这些优势可能会超过一些额外字节代码的成本。

答案 2 :(得分:4)

Try-catch-finally和try-with-resources具有基本相同的性能,因为它们在封面下生成基本相同的字节码。

然而,你的第二个版本(try..catch..finally)并没有完全正确,因为它(理论上)可能会在调用NullPointerException时导致不受欢迎的sc.close()。如果构建Scanner的行为导致异常被抛出,则sc将不会被分配,并且将为null

您应该在try..finally之外构建扫描仪并更改此内容:

Scanner sc = null;
try {
    sc = new Scanner(new File("file.txt"));
    ...

为:

Scanner sc = new Scanner(new File("file.txt"));
try {
    ...

或者,您应该在调用sc != null之前检查finally子句中的sc.close()。如果您在try..finally之外创建扫描仪,则不需要这样做,所以我建议您这样做。

要执行与try-with-resources相同的工作,您还需要在try..catch周围放置第二个sc.close()并使用空的catch块,以忽略在关闭期间抛出的任何异常。如果你这样做,我想你不必太担心空检查。

答案 3 :(得分:0)

传统的try-catch:在try块中,您的代码可能有一个异常,该异常将被抛出,然后被catch块捕获。然后catch块将处理异常。而且,如果您在try之前打开源文件(例如文件或其他东西),并且需要在finally中将其关闭,那么close()可能也会在finally中执行引发异常,它将替换try中引发的异常。这种情况通过SE 7之前的嵌套try-catch像这样

来解决
try
{
   try
  {
      code with exception;
  }
   finally
 {
      close();
 }

}
catch(Exception e)
{
  Deal the exception
}

这确实很复杂,因此在SE 7之后,当您完成try块时,我们将使用try-with-resource解决此问题,try(Here)中的资源将全部关闭。

参考“ Core Java”版本:基于SE 7的9