Functional Programming: y = f(x) ! Where does Java stand ?
What the heck ?
And, undoubtedly, we have a plethora of languages that cater to functional programming viz. Lisp, Caml, Clojure, Haskell (purely functional), and the list goes on; oh, of course, for Java lovers, there is Scala – where object oriented meets the functional.
And then again, since the time the JDK saw its way into machines, Java has almost become indispensable for server-side algorithms; why then should a Java lover dig forks into Scala, or such others ?!
Welcome – JDK 8 !
What’s the buzz ?
So, where does Java really stand out in functional programming compared to the aforementioned languages?
Being a contributing member of the Oracle Developers Network (formerly, the Sun Developers Network), I recall quite well, that it wasn’t just a mere six years back that the notion of functional programming was being crunched at the ODN meet-ups; rather, even before Haskell showed up, the Java dev community has been brainstorming about inclusion of functional programming in Java. There have of course been heated debates about the object-oriented vs functional approaches and how would one incorporate the latter with OOP being innate in Java.
The advent of Scala in 2004 instigated SUN further towards functional programming and to bring about the much needed FP features in Java.
The JDK did already include the fork/join framework enabling parallel computing. However, with fork/join – one must specify how the problems are partitioned.
With lambdas, the Java runtime performs this partitioning and combining of solutions.
Lambdas are first class functions, that can:
- be passed as arguments to other functions
- be returned from other functions
- assign functions to variables
- store functions in data structures
- let functions be anonymous
Lambda/FP delicacies, usage and good practices
Digest the following snippet:
And, then, let’s FP the above:
Oh wait! Did we just observe type defs gone ?
Lambdas incorporate type-inference alongside first-class functions – code clarity is enhanced, and the obvious verbosity with the anonymous inner class is reduced to a first-order function.
Reduced forEach since Java 8:
The above snippet can be replaced by:
which can be further reduced by an FP “eta expansion” method reference:
The magic of FP in Java doesn’t end here, of course.
Functional interface mapping:
Yes, the reductions are core to functional programming, and Java 8 lambdas support them.
Wherever we encounter a target type, lambda expressions can be put to use. In Java, we have target type in the following contexts:
- Variable declarations, assignments
- Function returns
- Method or constructor arguments
The Streams API and Lambdas can together help achieve significant levels of parallel execution on performing bulk operations over collections.
A stream filtering using lambda predicate:
Not being orthodox, yet, let’s get few highlights on the usage:
Use the annotation @FunctionalInterface for any interface that is intended to be used as a function.
For a huge project, this prevents breaking the contract of a functional interface, which was intended to be so with only one abstract method, ending up with more abstract methods added to it, accidentally. The annotation will make the compiler shout at anyone who tries to add any more than its only intended (abstract) function. Alongside this, also keep usage of default methods in functional interfaces to minimum.
Prefer the use of the standard functional interfaces provided in the java.util.function and other packages.
Needless to say, avoid duplicacy and rely on reusability – as long as we can reuse standard functionality, it’s better not to create our own.
Keep lambda expressions elegant.
In situations like the following:
Keep the lambda expression short, and extract out the extraneous lines of code into a separate method:
Avoid lambdas where method references (eta expansions) are possible.
Ideally, graceful usage of lambdas is the way to go. Make an overuse of them with lambdas expanding several lines of code and verbose functional interfaces and you end up with testing, debugging and maintenance issues.
So, what’s the big deal anyway ?
Apart from the fact that we can now exploit the beauty of functional programming keeping the object oriented aspects intact, it’s also evident that it would impact coding styles for programmers – crisp, concise and clear coding.
Of course, there are subtle valleys in the peaks of lambdas – limitations in Java 8 lambdas. The lambda functions only close over values, but not variables.
And you end up with the compiler screeching out: Local variable x defined in an enclosing scope must be final or effectively final.
So, full closures are yet to be supported in Java.
And yet, the impact of introducing lambdas in Java has been huge – Java has finally caught up with the buzz of FP. Stay tuned to JDK as further evolution would hopefully bring in more features towards first order functional programming in Java.