哪个更快,在java中尝试catch或if-else(WRT性能)

时间:2010-08-16 05:21:42

标签: java if-statement try-catch

哪一个更快:

这个

try {
  n.foo();
} 
catch(NullPointerException ex) {
}

if (n != null) n.foo();

13 个答案:

答案 0 :(得分:53)

if (n != null) n.foo();

更快。

答案 1 :(得分:51)

这不是一个更快的问题,而是一个正确的问题。

例外情况恰恰相反,例外

如果n可能null作为正常业务逻辑的一部分,则使用if..else,否则throw例外。

答案 2 :(得分:33)

显式测试空指针比使用异常处理快得多。

对于记录,使用异常的大多数的oherhead在异常对象的实例化中产生。特别是在调用fillInStackTrace()时必须:

  • 检查当前线程堆栈的每个堆栈帧,并
  • 创建数据结构以捕获堆栈帧详细信息。

在某些情况下,您可以通过重用异常对象或通过覆盖特定于应用程序的异常fillInStackTrace()方法来使其成为无操作来减少此问题。两种情况下的缺点是,将不再提供适当的堆栈跟踪来帮助您调试意外异常。 (这些都不适用于OP的例子。)

虽然异常实例化很昂贵,但异常抛出,传播和捕获也不是很便宜。


第二个原因是显式空值测试是一个更好的主意。考虑一下:

try {
    doSomething(a.field);
} catch (NullPointerException ex) {
    System.err.println("a.field is null");
}

如果NPE在doSomething(...)的调用中发生而不是在评估a.field表达式时发生了什么?当然,我们会捕获一个NPE,但我们会误诊它,然后继续尝试继续...错误地假设a.field未设置或其他东西。

将“预期的”NPE与“意外的”NPE区分开来在理论上是可行的,但在实践中非常困难。一种更简单,更健壮的方法是明确测试您期望的null值(例如使用if语句),并将所有NPE视为错误。

(我确信这就是@Mitch的意思是“将异常视为例外”,但我认为通过一个说明性的例子来解释事情会有所帮助......)

答案 3 :(得分:24)

答案并不像看起来那么简单,因为这取决于对象实际上为空的次数百分比。当这种情况非常罕见时(例如在0.1%的时间内),它甚至可能更快。为了测试这个,我已经使用以下结果(使用Java 1.6客户端)完成了一些基准测试:

Benchmaring with factor 1.0E-4
Average time of NullIfTest: 0.44 seconds
Average time of NullExceptionTest: 0.45 seconds
Benchmaring with factor 0.0010
Average time of NullIfTest: 0.44 seconds
Average time of NullExceptionTest: 0.46 seconds
Benchmaring with factor 0.01
Average time of NullIfTest: 0.42 seconds
Average time of NullExceptionTest: 0.52 seconds
Benchmaring with factor 0.1
Average time of NullIfTest: 0.41 seconds
Average time of NullExceptionTest: 1.30 seconds
Benchmaring with factor 0.9
Average time of NullIfTest: 0.07 seconds
Average time of NullExceptionTest: 7.48 seconds

这对我来说似乎很有说服力。 NPE的速度非常慢。 (如果需要,我可以发布基准代码)

编辑: 我刚刚发现了一个有趣的发现:使用服务器JVM进行基准测试时,结果会发生巨大变化:

Benchmaring with factor 1.0E-4
Average time of NullIfTest: 0.33 seconds
Average time of NullExceptionTest: 0.33 seconds
Benchmaring with factor 0.0010
Average time of NullIfTest: 0.32 seconds
Average time of NullExceptionTest: 0.33 seconds
Benchmaring with factor 0.01
Average time of NullIfTest: 0.31 seconds
Average time of NullExceptionTest: 0.32 seconds
Benchmaring with factor 0.1
Average time of NullIfTest: 0.28 seconds
Average time of NullExceptionTest: 0.30 seconds
Benchmaring with factor 0.9
Average time of NullIfTest: 0.05 seconds
Average time of NullExceptionTest: 0.04 seconds

使用服务器VM,差异很难说明。仍然:我宁愿不使用捕获NullPointerException,除非它确实是一个例外。

答案 4 :(得分:8)

如果n.foo()碰巧在内部抛出一个NPE,那么你需要进行长时间的调试(或者更糟糕的是,你的应用程序在生产中失败了......)。只是不要这样做。

你计划保存多少纳秒?

答案 5 :(得分:7)

我注意到我并不是唯一一位阅读Java专家时事通讯的人:)

除了语义差异这一事实(NPE不一定是由解除引用n引起的,它可能是由foo()中的某些错误引发的,以及可读性问题(try / catch对于读者而言比if更令人困惑),在n != null(与n == null的情况下,它们应该同样快。 if / else版本略有优势),但n == null if / else更快。为什么呢?

  1. if时,VM必须创建一个新的异常对象并填写其堆栈跟踪。堆栈跟踪信息的获取非常昂贵,因此这里的try / catch版本要贵得多。
  2. 有些人认为条件语句较慢,因为它们阻止了指令流水线操作,并且通过避免显式n != null,他们认为在n时它们便宜了。但是,当解除引用时,VM将执行隐式空检查 ...即,除非JIT可以确定{{1}}必须为非空,否则它可以在if / else版本中。这意味着if / else和try / catch版本应该执行大致相同的操作。但是...
  3. ... try / catch子句可能会干扰JIT如何内联方法调用,这意味着它可能无法优化try / catch版本以及if / else

答案 6 :(得分:3)

除了好的答案(使用例外的例外情况),我发现你基本上都试图避免在任何地方进行空检查。 Java 7将有一个“null safe”运算符,当调用n?.foo()而不是抛出NPE时,它将返回null。这是借用Groovy语言的。除非真正需要(即:处理库),否则还有一种趋势是避免在一个代码中完全使用null。有关此问题的更多讨论,请参阅此其他答案。 Avoiding != null statements

答案 7 :(得分:2)

处理异常通常很昂贵。 VM Spec可能会让您了解多少,但在上述情况if (n != null) n.foo();更快。

虽然我同意Mitch Wheat关于真正问题的正确性。

@Mitch Wheat - 在他的辩护中,这是一个非常人为的例子。 :)

答案 8 :(得分:1)

if 构造更快。条件可以很容易地转换为机器代码(处理器指令)。

替代方法( try-catch )需要创建NullPointerException对象。

答案 9 :(得分:0)

绝对第二种形式要快得多。在try-catch方案中,它会抛出一个exception来执行某种形式的new Exception()。然后调用catch块,这是一个方法调用,必须执行其中的任何代码。你明白了。

答案 10 :(得分:0)

首先是if ..然后..其他更好,由于其他海报指出的众多原因。

然而,它的速度并不快!它非常依赖于null对象与非null对象的比例。它可能需要数十万倍的资源来处理异常而不是测试null,但是,如果null对象每百万个对象只出现一次,那么异常选项会稍快一些。但速度不是那么快,它使你的程序可读性更低,更难以调试。

答案 11 :(得分:0)

答案 12 :(得分:0)

if-else更快,因为try-catch块引发了异常堆栈跟踪。 您可以将其作为If-Else块执行一条指令来进行评估,但Try-Catch将运行数千条指令以在发生异常时引发异常。

相关问题