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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3490770/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 02:03:16  来源:igfitidea点击:

Which is faster, try catch or if-else in java (WRT performance)

javaif-statementtry-catch

提问by Rakesh

Which one is faster:

哪个更快:

Either this

要么这

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

or

或者

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

回答by Mitch Wheat

It's not a question of which is faster, rather one of correctness.

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

An exception is for circumstances which are exactly that, exceptional.

一个例外是针对那些正是例外的情况

If it is possible for nto be nullas part of normal business logic, then use an if..else, else throwan exception.

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

回答by Boris Pavlovi?

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

is faster.

是比较快的。

回答by Stephen C

Explicitly testing for a null pointer is much faster than using exception handling.

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

For the record, mostof the oherheads in using exceptions are incurred in the instantiationof the exception object. In particular in the call to fillInStackTrace()which has to:

为了记录,大多数使用异常的其他人都在异常对象的实例化中引起。特别是在调用fillInStackTrace()中必须:

  • examine every stack frame for the current thread's stack, and
  • create a data structure to capture the stack frame details.
  • 检查当前线程堆栈的每个堆栈帧,以及
  • 创建一个数据结构来捕获堆栈帧的详细信息。

In some cases, you can reduce this by reusing the exception object, or by overriding an application specific exception's fillInStackTrace()method to make it a no-op. The downside in both cases is that proper stacktraces will no longer be available to help you debug unexpected exceptions. (And neither of these are applicable to the OP's example.)

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

While exception instantiation is expensive, exception throwing, propagation and catching are not exactly cheap either.

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



There is a second reason why explicit null testing is a better idea. Consider this:

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

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

What happens if an NPE happens within the call to doSomething(...)instead of during the evaluation of the a.fieldexpression? Sure, we'll catch an NPE, but we will misdiagnose it, and then attempt to continue ... incorrectly assuming that a.fieldis unset or something.

如果 NPE 发生在调用中doSomething(...)而不是在a.field表达式求值期间会发生什么?当然,我们会发现 NPE,但我们会误诊它,然后尝试继续……错误地假设它a.field未设置或其他什么。

Distinguishing an "expected" NPE from an "unexpected" NPE is theoretically possible, but in practice very difficult. A much simpler and more robust approach is to explicitly test for the nullvalues that you are expecting (e.g. with an ifstatement), and treat all NPEs as bugs.

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

(I'm sure that this is what @Mitch means by "treating exceptions as exceptional", but I think it helps to spell things out with an illustrative example ...)

(我确信这就是@Mitch 所说的“将异常视为异常”的意思,但我认为用一个说明性的例子来说明问题会有所帮助......)

回答by Marc

The answer to this is not as simple as it looks, because this will depend on the percentage of times that the object is really null. When this is very uncommon (say in 0.1% of the time), it might even be faster. To test this I've done some benchmarking with the following results (with Java 1.6 client):

这个问题的答案并不像看起来那么简单,因为这将取决于对象真正为空的次数百分比。当这种情况非常罕见时(比如 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

This seems pretty conclusive to me. NPE's are just very slow. (I can post the benchmarking code if wanted)

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

edit: I've just made an interesting discovery: when benchmarking using the server JVM, the results change drastically:

编辑:我刚刚有了一个有趣的发现:使用服务器 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

Using the server VM, the difference is hardly noticable. Still: I'd rather not use catching NullPointerException unless it really is an exception.

使用服务器虚拟机时,差异几乎不明显。仍然:我宁愿不使用捕获 NullPointerException 除非它确实是一个异常。

回答by gustafc

I notice I'm not the only one reading the Java Specialist's Newsletter :)

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

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 == nullif/else is a lot faster. Why?

除了存在语义差异这一事实(NPE 不一定是由解引用引起的n,它可能是由 中的某些错误引发的foo())和可读性问题(try/catch 对读者来说比 更令人困惑if),在这种情况下它们应该差不多快n != null(if/else 版本有一点优势),但是当n == nullif/else 快得多时。为什么?

  1. When 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.
  2. Some believe that conditional statements are slower because they prevent instruction pipelining, and by avoiding the explicit ifthey think they got away cheap when n != null. The thing is, however, that the VM will do an implicit null checkwhen dereferencing... that is, unless the JIT can determine that nmust 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...
  3. ... try/catch clauses can interfere with how the JIT can inlinemethod calls, which means that it might not be able to optimize the try/catch version as well as the if/else.
  1. 何时n == null,VM 必须创建一个新的异常对象并填写其堆栈跟踪。获取堆栈跟踪信息非常昂贵,因此这里的 try/catch 版本要贵得多。
  2. 有些人认为条件语句较慢,因为它们阻止指令流水线,并且通过避免显式,if他们认为它们在n != null. 然而,问题是,VM 将在取消引用时进行隐式空检查……也就是说,除非 JIT 可以确定它n必须是非空的,否则它可以在 if/else 版本中做到这一点。这意味着 if/else 和 try/catch 版本的执行应该大致相同。但...
  3. ... try/catch 子句可能会干扰 JIT 如何内联方法调用,这意味着它可能无法优化 try/catch 版本以及 if/else。

回答by Enno Shioji

If n.foo()happens to throw internally a NPE, you are off for a long debugging session (or worse, your app fails in production..). Just don't do it.

如果n.foo()碰巧在内部抛出 NPE,您将无法进行长时间的调试会话(或者更糟的是,您的应用程序在生产中失败......)。只是不要这样做。

How many nano-seconds do you plan to save, anyways?

无论如何,您打算节省多少纳秒?

回答by Bernard

Beside the good answers (use exceptions for exceptional cases) I see that you're basically trying to avoid the null checks everywhere. Java 7 will have a "null safe" operator that will return null when n?.foo()is called instead of throwing a NPE. That's borrowed from the Groovy language. There's also a trend to avoid using null altogether in one's code except when really needed (ie: dealing with libraries). See this other answer for more discussion on this. Avoiding != null statements

除了好的答案(在特殊情况下使用异常)之外,我看到您基本上是在尝试避免无处不在的空检查。Java 7 将有一个“空安全”操作符,它在n?.foo()被调用时将返回空值而不是抛出 NPE。这是从 Groovy 语言借来的。还有一种趋势是避免在代码中完全使用 null,除非确实需要(即:处理库)。有关此问题的更多讨论,请参阅此其他答案。 避免 != null 语句

回答by Andreas Dolk

The ifconstruct is faster. The condition can be easily translated to machine code (processor instructions).

如果结构比较快。该条件可以轻松转换为机器代码(处理器指令)。

The alternative (try-catch) requires creating a NullPointerException object.

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

回答by linuxuser27

It is usually expensive to handle exceptions. The VM Specmight give you some insight into how much, but in the above case if (n != null) n.foo();is faster.

处理异常通常很昂贵。该VM规格可能给你一些洞察到多少,但在上述情况下if (n != null) n.foo();更快。

Although I agree with Mitch Wheat regarding the real question is correctness.

尽管我同意 Mitch Wheat 关于真正问题的正确性。

@Mitch Wheat - In his defense this is a pretty contrived example. :)

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

回答by fastcodejava

Definitely second form is much faster. In the try-catchscenario, it throws an exceptionwhich does a new Exception()of some form. Then the catchblock is invoked which is a method call and has to execute whatever code is in it. You get idea.

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