Hacker News new | ask | show | jobs
by EdSharkey 3431 days ago
Someone smarter than me can explain why and how, but I had also heard that streams in Java can perform better than equivalent imperative code as well as being null-safer.

This is because the standard library can forego memory allocation for temporary data structures implied in expressions throughout the stream statement. Also, the Java 8 VM can apply other aggressive optimizations to the lambda functions to inline them.

2 comments

Sadly, no. Code written in this style will typically run more slowly, or be equivalent at best. Streams can perform better if you make them parallel and have lots of data as then you can more easily spread out over multiple cores (which is the point of streams), but most cases aren't like that.

When you heavily use stream constructions, you're relying on the JVM to:

• Synthesise classes for the lambdas.

• Inline the map/filter/fold calls and then inline the lambdas too. The JVM doesn't make any guarantees about inlining and may unpredictably bail out. If inlining doesn't happen then profile pollution will kill off some of the other optimisations the JVM does.

• Escape analyse any temporary objects created like iterators and then scalar replace them.

• Try and do some loop fusion, but I'm not sure to what extent the JIT compilers can do that.

This is a long list of complex and often fragile optimisations. If any of them don't get applied then you end up with virtual method calls, objects being created, poor cache utilisation etc. Sure objects that die young are cheap but they aren't entirely free. It's still best to avoid them.

The reality is that writing traditional style code is going to be more efficient or at least more reliably efficient than functional style code for the forseeable future.

Note that the JVM has a much easier time of it when using Kotlin's support for lambdas and functional programming because the inlining is guaranteed to be done by the Kotlin compiler not the JVM, and that fixes a lot of issues with profile pollution and unpredictable performance drops.

Theoretically there's all kinds of optimizations possible, but I don't think Java/the JVM does a lot of them. The main advantage you'll get is lazyness.