One evening around 5:30 PM, I made my self a cuppa and settled down, for I was about to start refactoring a twenty years old piece of code that I found on the Internet (😉).
The number of lines in that java file were more than the distance between India and South Africa.
It was full of code duplication, method length was so long that Sonar Qube gave up during instrumentation! 😄
I picked one method and after (what felt like) a few hundred miles of scrolling, I finally stopped at the deepest branch.
I used my IDE shortcut to extract that piece of code into a method, followed by another shortcut to generate a test file.
The extracted method had a for loop, a if condition and a return statement:
For loop was looping a list.
If the condition was met then that object was collected in an another list.
The final list was then returned from the method.
Basically a filter pattern!
I wrote a few tests to see how the method performed for different input types and then started with refactoring, which was to replace loop-gibberish with stream-filter-collect-return.
Once done, as I basked in the beauty of the newly refactored method, with bug free assurance provided by an army of automated test cases.
A thought popped up in my mind:
Rahul: “what if the gibberish looking for-loop code had better performance than the concise-and-pretty looking stream code?”
It was an intriguing thought, since ”For-Loop” is well a simple loop compared to Stream filter-collect logic!
So the young and naive code bench-marker I was, I started by writing two tests (For-Loop VS Stream) and tried to compare the performance by printing the execution time.
1 2 3 4 100 records: For-loop won (YAY) 500 records: For-loop won (YAY) 1000 records: Stream won (Hmm…) 10000 records: Both had same execution time; 0 milliseconds (whaaat?)😕
Well I forgot about something called JIT (just in time), as the number of code iterations increase, this thing goes from being sleepy to.. well.. being freaking brilliant!
JIT compiler has been added in java to improve the run time execution of programs.
When JIT kicks in, it does an on fly code conversion and optimization hence reducing overall execution time.
To name a few optimizations done by JIT:
- dead code elimination
- null check elimination
- branch prediction
- loop unrolling
- inlining methods
Now my test case was calling the refactored code, but it did nothing with the result.
When JIT kicked in, it saw test case was doing nothing with the filtered list, so it marked the entire code as dead code (not being used) and eliminated it, hence the name Dead-Code-Elimination.
Since no code actually executed the run-time came down to 0 milliseconds! 😄