Java Lambda Performance — With a little bit Haskell as well…

Hi there folks!

Today I´m going to test how the Java lambda performs over with their implementation of lambda functions.

Overview

The Stack Overflow survey tells us that the most loved functional languages are Clojure and Elixir, by the time of this article publishment:

But the most pure functional language is Haskell, if you want to learn functional programming it’s simply the best choice. There is a book Learn You a Haskell that you can read for free online.

Starting with Java 8 the language offered some of the functional programming style features with lambdas and Functional Interface. For the ones that worked with Anonymous Classes will find it pretty similar, in reality they are a new form to implement those.

How it works: There is a new annotation, @FunctionalInterface, it indicates that the annotated Interface has only one abstract method that can be expressed as a lambda and the JVM will infer the Interface for you. There is no necessity to use the annotation, but you still need to implement only one abstract method.

Although the language assumes some of the functional paradigm it does not include others, like imutable state for example.

The performance

I designed a simple experiment to see how much it costs the JVM to use lambda over pure Java. I’m not trying to say that we never should use lambda or we should throw away pure Java code to be more functional. The objective is to create tools to test and have a more accurate decision of how to implemente those, even more because having the functional style can bring our code to another level of sophistication and a totally new set of solutions with High-order Functions that we would have a lot of work to make before or even would be impossible to do.

The algorithm is pretty simple, using JMH to make a benchmark of how the algorithm performs in different implementations.

1 — We’ll make a iteration over a number of times, from 10 to 1,000,000, increasing in power of 10.

2 — For each loop we’ll map the value to add 10

3 — Then we’ll be reduce and sum all the values

You can find the code here.

The results are the following:

When we just pass the lambda in over a Stream pipeline we see that it takes more than nanoseconds to finish the task with 10 iterations, 1 nanosecond is 10E-9, and it loses performance really fast as grows the number of iterations.

Let’s see the others methods:

As you can see there is no gain in the changes we made, they all have the same result.

Now let´s see how the pure Java goes:

The gain in performance is really impressive, we start with almost 1 nanosecond with 10E-8 and finish with 1 millisecond.

So the problem is functional programming?

Well… let’s see that.

Haskell for the rescue

Let’s see how it goes:

The execute_seq does the same algorithm as the Java one, we now used the same strategy as JMH and made 2 iterations of warm-up and 3 of execution. Let’s see the results of the execute_seq with parameter 10:

There are some variations in warm-up but the fact it does the algorithm in nanoseconds is already better than the pure Java implementation.

Let’s make a plot.

Surprisingly as the number of iteration grows Haskell do not grows exponentially.

Here is a plot comparing both results:

As you can see that Java grows the time needed to perform the task as the number of iterations grows, Haskell is so optimized for the task that it take a while for it to grow, although Java in a pure form does a lot better than the lambda counterpart.

Conclusion

There is still some place for further testing, I used the openjdk and in the future I’ll make an article using GraalVM and comparing both results to see if they have a better performance over the task and use the Clojure as it is a functional language running over the JVM.

I hope you people liked it, until next time!

Writing to make ourselves better programmers.