10

Normally I prefer null check. But in current scenario I know that most of the time my if condition will pass and there are few legitimate scenario where object may be null.

Also, load is huge (about 5 million calls / hour)

Now I trying to find which way is better from performance perspective. Already checked try/catch vs null check in java but my case is unique.

Also checked Which is faster, try catch or if-else in java (WRT performance) but both this one and above ones are in generic context where knowledge of pass/fail ratio is not available.

public void process(Job job) { //... some code which processes job SubJob subJob = job.getSubJob(); if(subJob != null) { // 99% of the time this will pass //.. do something } } 

try/catch version

public void process(Job job) { //... some code which processes job SubJob subJob = job.getSubJob(); try { //.. do something }catch(NullPointerException e) { //This may occure only 1% of the time. //... } } 

Update:

Winner is null check. In Try/catch, internally JVM will do null check and throw NPE anyway and on top of that exception handling in JVM (creation of stack etc) will be overhead. Also as per another answer, modern CPUs are intelligent enough to handle these scenario with good prediction which in my unique case will always work in favor.

I also wrote program (posted below under my name) and results are clearly indicating that null check is way better on my AMD processor.

Thank you folks for guiding me.

7
  • 5 millions calls per hour is less that 1400 calls per second, and a null check probably only takes a few tens of microseconds. What performance did you see when you compared these two? Commented Oct 22, 2015 at 17:49
  • Why don't you stress test it and find out... Commented Oct 22, 2015 at 17:49
  • You should be able to setup a test to compare the 2 methods and see which one is more efficient. Commented Oct 22, 2015 at 17:50
  • 1
    Why don't you change it so that every Job always has a SubJob, even if it's a NO-OP? Commented Oct 22, 2015 at 17:50
  • 2
    @DavidConrad it's probably closer to one nanosecond per null check with a high chance that branch prediction will make it 0 most of the time... Commented Oct 22, 2015 at 18:09

6 Answers 6

8

TL;DR: If you don't do the null check in your code, the runtime will insert one for you anyway. Null checks almost always have zero cost.


You need to view this problem from the perspective of HotSpot or an optimizing JIT compiler:

When you call a method on an object variable

someObject.callMethod() 

then the runtime needs to throw a NPE if the variable is null (Pseudo ASM):

check someObject ref not null else throw NPE invoke 'callMethod' on 'someObject' 

Now sometimes the runtime can be sure that a variable is not null. This analysis is called null check elimination.

-- no need: check someObject ref not null else throw NPE invoke 'callMethod' on 'someObject' 

The clue is that your check in the Java source code

if (someObject != null) 

is good enough to prove to the runtime that the variable is not null.

The rationale:

Always prefer a null check over catching a NPE. If you don't do the null check then the runtime will insert it for you.

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

2 Comments

good blog post about null check elimination: jpbempel.blogspot.de/2013/09/null-check-elimination.html
wow. I missed it totally. Yes, you are right, null check will be done anyway.
3

Go with the null checks, the processor will pipeline it and should always "ignore" the if and go on through to the statement.

Similar, talks about pipelining: Why is it faster to process a sorted array than an unsorted array?

2 Comments

Nice read. So If i assume that current array of processors are way better then past, my if condition will have no effect on total time. But will it still take cup cycle anyway?
The pipelining is designed to not slow down the processor, it should assume that it's not null and keep processing as if it's instantiated. The processor will then on the side attempt to check if it was right on it's guess of non-nullness.
3

I would strongly lean to your existing preference for the null-check. For a situation that has a legitimate null condition, I'd say you should check for null and save a null-pointer exception for something that "never happens." I should mention that this is more of a paradigm preference than a performance-based one. However, for me, there would have to be an enormous benefit in performance and an extreme need to warrant the approach.

That being said, a previous comment stating that exception overhead would only be incurred 1% of the time, in the case of an exception, assumes that the "setting up" of the try block takes no overhead. I'm not sure this is the case.

Comments

2

There are two aspects here, one is performance and the other is design. You can say which is better is not question you should ask, is it good enough is what you need. If 99% of the time it is not null, then branch prediction will save your day, and JIT might optimise more. But whatever you choose, you have to do something with this special-case. What do you do? You throw an exception or catch the NPE and re-throw it again?Then, exceptions might be the performance bottleneck and not the mechanism .

I would write this myself.

SubJob subJob = job.getSubJob(); Objects.requireNotNull(subJob); 

Comments

1

For people who want to see the code I ran for testing...

public class TestMainResuse { static int load = 1000000; public static void main(String[] args) throws Exception { Object[] objects = new Object[load]; for(int i = 0; i < load; i++) { if(i % 100 == 0 ) objects[i] = null; else objects[i] = new Object(); } withTry(objects); withIf(objects); withTry(objects); withIf(objects); withTry(objects); withIf(objects); withIf(objects); withIf(objects); withTry(objects); withTry(objects); } public static void withTry(Object[] objects){ long startTime = System.nanoTime(); for(int i = 0; i < load; i++) { try { objects[i].getClass(); } catch (NullPointerException e) { //System.out.println("this"); } } System.out.println(" try took "+ (System.nanoTime() - startTime)); } public static void withIf(Object[] objects){ long startTime = System.nanoTime(); for(int i = 0; i < load; i++) { if(objects[i] != null) { objects[i].getClass(); } } System.out.println("null took "+ (System.nanoTime() - startTime)); } } 

Output (diff in nanos):

 try took 6906539 null took 3801656 try took 13380219 null took 87684 try took 1036815 null took 79558 try took 1021416 null took 10693 try took 1020989 null took 1711 null took 1284 null took 1283 null took 1283 null took 1283 null took 1711 try took 1038954 try took 1106107 try took 1040237 try took 1020134 try took 1028261 

Comments

0

How about reversing your if statement

if(subJob == null){ //do something to fix it; } 

This way (as you claim) this piece of code will be invoked only 1% of time¨and rest of the time your program will not care about it.

5 Comments

or even an else off of the if statement to fix it
I am trying to avoid if condition itself to save cpu cycle.
@austinwernli But those are additional keystrokes, and we all know every programmer has finite number of keystrokes left until he expires
@TheLaw I'm pretty sure its that he wants to remove the check altogether, not about typing a few more letters
@Jags Only two alternatives then are to either prevent subJob being constructed as null, or having unchecked exception in your code, which is devil incarnate. When someone finds a way to eliminate null checks altogether, without checking them or making conditions for them to no occur, he will be the next big thing. And to answer your question then, using if is definetly better idea than try-catch.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.