• Post Reply Bookmark Topic Watch Topic
  • New Topic

How to choose the best functional solution?  RSS feed

 
Roel De Nijs
Sheriff
Posts: 11338
177
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
With the introduction of lambdas/predicates and functional programming in Java 8 you get (almost) infinite possibilities to solve any problem. For each problem you'll have a bunch of non-functional and functional solutions. How do you know which one will be the best one (as in most performant one)?

For example, suppose this simple problem: print all the odd numbers in a list greater than 15 without any duplicates. I can at least think about 2 solutions:And from these solutions you could create 2 other alternatives by just switching the filter statements. And maybe another alternative could be to combine both filter statements into one:

When I was at Devoxx 2014, I attended a few functional programming presentations. In one of them a very complex problem (about movies and actors, I believe) was solved using functional programming in Java. The Java 8 code of the 1st solution looked great, (even more important) made sense and returned the correct result almost instantly, so everything seemed just fine. But when a very big dataset was used, the program took minutes to complete with exactly the same code.

And somewhat related: does the compiler currently perform optimizations for you (or maybe in the future)? Just like when you write a sql query it's often optimized by a query optimizer.

Kind regards,
Roel
 
Jesper de Jong
Java Cowboy
Sheriff
Posts: 16028
87
Android IntelliJ IDE Java Scala Spring
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
There are two kinds of operations you can do on a stream: intermediate operations and terminal operations (see the API docs of the package java.util.stream).

Intermediate operations return a new stream, while terminal operations return something else. You put a terminal operation on the end of a stream pipeline. In your examples, filter() and distinct() are intermediate operations, and collect() and forEach() are terminal operations.

Streams are processed lazily - it is not so that each operation in a stream runs on all the elements before it passes the result to the next operation; an intermediate operation is only executed when needed (the terminal operation is "pulling" data through the pipeline element by element).

Your first example is better than the other two. Why: Because in the second and third example you have two terminal operations. First you collect everything in a Set, and then you do forEach on the Set. In your first example, the Set that holds all the results temporarily is not necessary.
 
chris webster
Bartender
Posts: 2407
36
Linux Oracle Postgres Database Python Scala
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You might be interested in the Functional Programmign Patterns book. It's aimed at Scala/Clojure, but the Scala stuff might map OK into Java 8 or at least give you a feel for how these things work in FP. One of the interesting aspects of the book is how many OOP design patterns are rendered redundant in a properly functional programming language e.g. all those OO patterns that are basically about passing behaviour around.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!