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 s=(s==null?t:s);
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.
Comments?
Author’s Note: Repost.