36

Which one is faster:

Either this

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

or

if (n != null) n.foo(); 
9
  • 37
    How about "Which is more readable?" Performance is your last concern. Commented Aug 16, 2010 at 5:22
  • 4
    Using try-catch clause this way is definitely bad idea. Also try-catch results in instantinating of new object (the exception). Thus I'd say that (n!=null) is faster in case you have a lot of cases where n == null. Also n!=null is superfast construct. Commented Aug 16, 2010 at 5:26
  • 8
    "Also try-catch results in instantinating of new object (the exception)". No, it does not. Throwing an exception does. Commented Aug 16, 2010 at 5:41
  • 7
    Hmm, funny that this is the subject of the latest Javaspecialists newsletter quiz. Heinz M. Kabutz does argue that the first form is indeed very bad for performance. He does however provide one additional piece of information: n is null 10% of the time. Commented Aug 16, 2010 at 5:50
  • 23
    They're different... the first form will also catch NPEs thrown from within foo() Commented Aug 16, 2010 at 5:56

12 Answers 12

54

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 n to be null as part of normal business logic, then use an if..else, else throw an exception.

Sign up to request clarification or add additional context in comments.

4 Comments

As usual, the first poster who says "don't do premature optimization" gets the most upvotes. This question is not about what is correct, best, or most readable, but what is fastest. The OP most likely found this question in the last issue of the Java Specialist Newsletter, which means they're probably interested in learning the reason why the fastest version is faster (and so deepening their understanding of the VM internals), rather than thinking about implementing this in production code.
@gustafc: Whilst being first sometimes gets the most upvotes, my daily limit was reached some time ago. I still stand by my answer. I'm sure you're aware that the question asked is not always the real question. There was no mention of VM internals. Had there been I might have phrased my answer differently.
Yes, it was a question of which is faster -- look at the original OP's question. It may not be "best practice" to prematurely optimize the solution, but maybe the OP was interested in learning something about how these things are implemented.
@Ralph: sometimes you move past what is asked, and answer the real question.
52
if (n != null) n.foo(); 

is faster.

9 Comments

@Rakesh Correctness is always more important than speed. A program that runs fast but is incorrect is useless.
You can still get a NPE if something in foo() throws it. Since I don't know what's inside of foo() asserting this is incorrect. So, if inside foo() you have to do a lot of "if( x != null)" then catching the exception here is faster.
@Jesper correctness alone does not answer the question. It is unimportant if it is premature optimisation or not. Answer the question and add a warning to your answer instead of just repeating the "premature optimisation" gospel to get upvoted
@Mitch Wheat yes, because it gets the people who copy paste it up-voted for something which was not asked. There is no reason why answering the question and giving good advise would be mutually exclusive. Not to say that premature optimisation is not evil, but stand alone it is not a valid answer to any question about performance.
@Rakesh Juyal: Good comment! I really bothers me when someone asks a question and the responses all include "What is the use case?", even when the question is clear. Isn't it enough to want to know the answer, without having to justify the question?
|
36

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

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

  • 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.)

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

(I should add that I agree with @Mitch's general point about premature optimization. However, the cost of an exception that actually occurs is large enough that it is best to avoid using them for routine null checks; i.e. if you intend to catch and recover from the NPE.)


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.field expression? Sure, we'll catch an NPE, but we will misdiagnose it, and then attempt to continue ... incorrectly assuming that a.field is unset or something.

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 null values that you are expecting (e.g. with an if statement), and treat all NPEs as bugs.

(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 ...)


Finally, it is worth nothing that in

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

there are actually two null tests:

  • There is an explicit test in n == null.
  • There is also an implicit check in n.foo().

However, the JIT compiler should be able to optimize away the second check and the associated native code that throws the NPE. In fact, the addition of the if (n != null) is likely to add zero runtime overhead once the code has been compiled to native code.

1 Comment

This should be the chosen answer since it actually answers the question and goes in detail about what is faster and why.
26

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):

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)

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

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.

9 Comments

@Marc: Beware - Java micro-benchmarks are very difficult to get right. Without seeing your code, it is impossible say whether your results are meaningful.
@Stephen C - I've posted the code on github - github.com/marcdejonge/javabenchmarking . Maybe we can add more of these benchmarks in the future and build a complete framework for microbenchmarks.
@Marc: I looked at these benchmarks, and they are dodgy, IMO. The JIT compiler may have figured out that both execute methods were effectively no-ops and optimized them away. Also. you are doing nothing to ensure that the methods are JIT compiled, or to allow for the CPU overhead of JIT compilation.
@Stephen C - The JIT compiler can not optimize the function away, because it won't know which side effects the function has. Furthermore, the test is run 10 times to allow the first (and maybe second one) to be ignored. When calculating the average times, the fastest and slowest times are ignored.
BTW, I found out why the server version is so much faster: it doesn't create a stacktrace. Apparently the JIT compiler knows that the stacktrace is not used and it returns an empty (singleton) instance of the NullPointerException.
|
8

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.

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

Comments

8

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?

  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 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...
  3. ... try/catch clauses can interfere with how the JIT can inline method calls, which means that it might not be able to optimize the try/catch version as well as the if/else.

Comments

3

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

6 Comments

I think the elvis operator ( b?.foo() ) has actually been excluded from JDK 7, and there are no plans to include it.
"There's also a trend to avoid using null altogether" I don't think this is a trend. Returning/using null has been a bad practice for ever. I haven't find yet a situation under which a method should return null instead of throwing an exception.
@Ubersoldat: How about specifying an unspecified value? Do you throw an exception if the app does not have some data filled in (yet)?
@Marek well, I think that is an exceptional condition for which the given process is not ready to handle, since it shouldn't be called if the data is not there for it to handle it.
@Ubersoldat: Are you really throwing an exception instead of returning null meaning e.g. "delivery date not yet known"?
|
2

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

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

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

1 Comment

Exceptions are only expensive if they happen (and I think the cost is more on the throw than on the catch). If the exception (almost) never happens, not checking for null might be faster. To defend the OP, in Python, the recommended practice is to let the exception happen.
2

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

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

Comments

0

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

Comments

0

Firstly the if.. then .. else is better, for numerous reasons pointed out by the other posters.

However it is not necceseraly faster! It depends entirly on the ration of null objects to not null objects. It probably takes a hundreds of thousands times the resources to process an exception rather than test for null, however, if a null object occurs only once for every million objects then the exception option will be slightly faster. But not that much faster that its worth making your program less readable and harder to debug.

1 Comment

-1 for incorrect information. In the JIT compiler of the Oracle Hotspot VM "Null checks can be hoisted manually, and suppress implicit null checks in dominated blocks.", i.e. both the if and the try approach perform the same number of checks. Therefore, the if version is never slower on this VM once the JIT has run.
0

This issue has discussed recently by Dr. Heinz:

http://javaspecialists.eu/webinars/recordings/if-else-npe-teaser.mov

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.