Monday, 22 January 2018

3 Reasons why You Shouldn’t Replace Your for-loops by Stream



Java developers will need to practice, and come up with an intuitive understanding of when to use FP, and when to stick with OO/imperative. With the right amount of practice, combining both will help us improve our software.

1. Performance – you will lose on it

In many cases, performance is not critical, and you shouldn’t do any premature optimisation – so you may claim that this argument is not really an argument per se. But I will counter this attitude in this case, saying that the overhead of Stream.forEach() compared to an ordinary for loop is so significant in general that using it by default will just pile up a lot of useless CPU cycles across all of your application. If we’re talking about 10%-20% more CPU consumption just based on the choice of loop style, then we did something fundamentally wrong. Yes – individual loops don’t matter, but the load on the overall system could have been avoided.
An entirely different aspect of scaling is about scaling performance, i.e. to make sure that an algorithm that works for 1 piece of information will also work well for 10 pieces, or 100 pieces, or millions. Whether this type of scaling is feasible is best described by Big O Notation. Latency is the killer when scaling performance. You want to do everything possible to keep all calculation on a single machine. This is often also referred to as scaling up
Here’s Angelika’s benchmark result on an ordinary loop, finding the max value in a list of boxed ints:
ArrayList, for-loop : 6.55 ms
ArrayList, seq. stream: 8.33 ms
In other cases, when we’re performing relatively easy calculations on primitive data types, we absolutely SHOULD fall back to the classic for loop (and preferably to arrays, rather than collections).
Here’s Angelika’s benchmark result on an ordinary loop, finding the max value in an array of primitive ints:
int-array, for-loop : 0.36 ms
int-array, seq. stream: 5.35 ms
Premature optimisation is not good, but cargo-culting the avoidance of premature optimisation is even worse. It’s important to reflect on what context we’re in, and to make the right decisions in such a context.

2. Readability – for most people, at least

We’re software engineers. We’ll always discuss style of our code as if it really mattered. For instance, whitespace, or curly braces.
The reason why we do so is because maintenance of software is hard. Especially of code written by someone else. A long time ago. Who probably wrote only C code before switching to Java.
Things start getting a bit more interesting and unusual. I’m not saying “worse”. It’s a matter of practice and of habit. And there isn’t a black/white answer to the problem. But if the rest of the code base is imperative (and it probably is), then nesting range declarations and forEach() calls, and lambdas is certainly unusual, generating cognitive friction in the team.
You can construct examples where an imperative approach really feels more awkward than the equivalent functional one, as exposed here:

3. Maintainability


Difficult-to-maintain source code is a big problem in software development today, leading to costly delays and defects. Read the first chapter from Building Maintainable Software, Java Edition, to learn exactly what maintainability means and how it has an impact on business.
If you have work in large organization e.g. Investment banks e.g. Barclays, Citibank, or big Insurance companies you will find how important is support and maintenance of production applications are. There are several more software engineers working in support role then programmers developing software. You have L1, L2, and L3 support and then dedicated support team for every application. This means support is really important.

But, when programmers develop an application, they focus on features and speed of development e.g. how quickly a feature is ready for testing etc, and to achieve these many programmers including myself in past often ignore things which matter a lot in production.



From a maintenance perspective, a functional programming style can be much harder than imperative programming – especially when you blindly mix the two styles in legacy code.

Conclusion

This is usually a pro-functional programming, pro-declarative programming blog. We love lambdas. We love SQL. And combined, they can produce miracles.
But when you migrate to Java 8 and contemplate using a more functional style in your code, beware that FP is not always better – for various reasons. In fact, it is never “better”, it is just different and allows us to reason about problems differently.

No comments:

Post a Comment