≡ Menu

Repost: Rocket Java: if(s==null) {s=t} vs. s=(s==null?t:s);

From online again, names concealed to protect the guilty:

I’m trying to figure out the shortest way to do this:

if (anotherString != null) s = anotherString;

Now, if you’ll pardon the stream of consciousness, through discussion it turns out he’s trying to work out the shortest form:

s=((anotherString != null)? anotherString:s);

Or, paraphrasing in perl:

a = b if b

Interesting question, sort of. The “shortest form” is up to the coder, of course; why not count keystrokes if that’s what you actually care about? That said, it got me wondering: which is most efficient?

Well, my first thought is, as usual: I don’t know. I’d have to test. So that’s what I did: write two methods, one which does an if() and assigns if the expression evaluates to true, and the other which uses the ternary syntax.

I ran the expressions in a loop, 100,000 times, and ran the loops twice each (just in case warmup affected one or the other). Before we look at the times, though, here’re the expressions tested:

// here we generate the things to test.
// randomValue() returns null roughly half the time.
String s = randomValue();
String t = randomValue();

// evaluation, then conditional assignment...
if (s == null) {
   s = t;

// ternary assignment

My first thought was that the former would be faster, because it does the assignment only if s is null. That’s the only substantive difference, really; s and t both call randomValue() before the evaluation/assignment.

The bytecode sort of looks the same way. Here’s the if() form, in bytecode:

   36:  aload   5
   38:  ifnonnull       45
   41:  aload   6
   43:  astore  5
   45:  aload_3

And here’s the ternary expression:

   36:  aload   5
   38:  ifnonnull       46
   41:  aload   6
   43:  goto    48
   46:  aload   5

Note the second “aload 5” there!

Here’s the thing: this bytecode is just what’s generated from javac. It’s not what runs; HotSpot converts all this, and … HotSpot optimizes. The bytecode doing more loads doesn’t mean that the executed code runs more loads, nor does it mean that a load and a store are equivalent in runtime. So looking at the bytecode is interesting, but not really very relevant – not to me, at least.

(Josh Bloch would be able to tell you a lot more about what goes on with a given bytecode block than I could. But he’d also probably not bother responding to such a simple query in the first place. Heck, even I am responding because I’m curious, and I’m willing to expose my faulty thought processes for everyone to see.)

So running the code yielded some interesting results, sort of. After a warmup, the if() ran in 70ms longer (roughly, and consistently) than the ternary expression.

I’m not surprised; my initial thought was that the opposite would happen, but hey, this is why I thought I’d test before making a declaration in the first place.

Testing always trumps assumption.


Author’s Note: Repost.

{ 0 comments… add one }

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.