Rak*_*esh 35 java if-statement try-catch
哪一个更快:
这个
try {
n.foo();
}
catch(NullPointerException ex) {
}
Run Code Online (Sandbox Code Playgroud)
要么
if (n != null) n.foo();
Run Code Online (Sandbox Code Playgroud)
Mit*_*eat 53
这不是一个更快的问题,而是一个正确性的问题.
例外的情况恰恰相反.
如果n
可以null
作为正常业务逻辑的一部分,那么使用an if..else
,否则throw
为异常.
Bor*_*vić 53
if (n != null) n.foo();
Run Code Online (Sandbox Code Playgroud)
是比较快的.
Ste*_*n C 34
显式测试空指针比使用异常处理快得多.
对于记录,大多数使用异常的oherhead都是在异常对象的实例化中产生的.特别是在呼叫fillInStackTrace()
中必须:
在某些情况下,您可以通过重用异常对象或通过覆盖特定于应用程序的异常fillInStackTrace()
方法来使其成为无操作来减少此问题.两种情况下的缺点是,将不再提供适当的堆栈跟踪来帮助您调试意外异常.(这些都不适用于OP的例子.)
虽然异常实例化很昂贵,但异常抛出,传播和捕获也不是很便宜.
第二个原因是显式空值测试是一个更好的想法.考虑一下:
try {
doSomething(a.field);
} catch (NullPointerException ex) {
System.err.println("a.field is null");
}
Run Code Online (Sandbox Code Playgroud)
如果NPE在调用中发生doSomething(...)
而不是在a.field
表达式的评估期间会发生什么?当然,我们会捕获一个NPE,但我们会误诊它,然后继续尝试继续......错误地认为这a.field
是未设置或其他事情.
区分"预期的"NPE和"意外的"NPE在理论上是可行的,但在实践中非常困难.一种更简单,更健壮的方法是明确地测试null
您期望的值(例如使用if
语句),并将所有NPE视为错误.
(我确信这就是@Mitch所说的"将异常视为例外"的意思,但我认为通过一个说明性的例子来解释事情是有帮助的......)
Mar*_*arc 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
Run Code Online (Sandbox Code Playgroud)
这对我来说似乎很有说服力.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
Run Code Online (Sandbox Code Playgroud)
使用服务器VM,差异几乎不可察觉.仍然:我宁愿不使用捕获NullPointerException,除非它确实是一个例外.
如果n.foo()
碰巧在内部抛出一个NPE,那么你需要进行长时间的调试(或者更糟糕的是,你的应用程序在生产中失败了......).只是不要这样做.
无论如何,你打算保存多少纳秒?
I notice I'm not the only one reading the Java Specialist's Newsletter :)
Apart from the fact that there's a semantic difference (the NPE isn't necessarily caused by dereferencing n
, it might have been thrown by some error in foo()
), and a readability issue (the try/catch is more confusing to a reader than the if
), they should be about equally fast in the case when n != null
(with the if/else version having a slight advantage), but when n == null
if/else is a lot faster. Why?
n == null
, the VM must create a new exception object and fill in its stack trace. The stack trace info is really expensive to acquire, so here the try/catch version is far more expensive.if
they think they got away cheap when n != null
. The thing is, however, that the VM will do an implicit null check when dereferencing... that is, unless the JIT can determine that n
must be non-null, which it can in the if/else version. This means that the if/else and try/catch versions should be perform approximately the same. But...