Functional Programming dates all the way back to Lisp in the 1950s. Imperative, procedural, and object-oriented programming each had their long runs as paradigms, but functional programming never quite broke through to the mainstream.
But with Java 8’s support of lambda expressions, type inference, syntactic sugar for static methods, and new APIs like Stream and CompletableFuture, there is a renaissance around functional programming. Oracle is basically taking 9 million Java developers back to the future.
(Related: Another take on functional programming)
So let’s take a look at some of the key concepts that Java shops need to be familiar with as they weigh the opportunities that functional programming offers, and try to form a strategy for how they approach functional directions in Java 8:
Lambdas: It’s already a very common pattern in Java to do callbacks using anonymous classes when there is an outside event happening. Lambdas are basically just that, but with more syntactic sugar around it. The simplest explanation of lambdas is that they’re a function: They take input, process it and yield output. You can do this in Java now. But it’s extremely cumbersome. You have to define a new class that implements one method that basically does what the lambda does. So it’s like five or six lines of code instead of having it written as a single line of code. But for what it does, it makes no difference. It just looks different.
Functions: Functions are extremely simple. They are nameless interfaces with a single method—they just rely on input and output type. In libraries, you have well-established names for common functions that are always the same and have the same semantics, often even across languages, such as map, filter, reduce, fold, etc. A function takes a string and returns something, which makes it extremely easy to reuse and compose. When defining classes in Java, you as the developer have come up with your own API for each class you define: [setFoo(foo), getBar() and doStuff()].
This means that every new user of this API will have to learn your custom API—the names that you come up with—which makes it very hard to compose things, since you needed to relearn the API for every single new API you use. This makes object-oriented components extremely hard to compose and reuse. Another benefit with using functions is that they only do one well-defined thing, which makes them very easy to reuse, a big contrast to objects that tend to do multiple things and have tangled responsibilities, sometimes dependent on the context in which they are used.
Immutable State: In the single-threaded world of the 1980s and 1990s, dealing with state was easier. But managing state with multicore… well, it opens Pandora’s box. Many Java developers are trying to shoehorn all of these states into a perceived reality of running on a single core. Functional programming languages like Scala, Erlang and Haskell encourage immutable states, which basically means being able to better reason about the effects of what is happening at a given time. In Java the default is mutable, so you have to be very careful when using lambdas in Java if you assume a functional style, because all the collections are by default mutable. So if you use it like you used to, then things will break all over the place.
Asynchronicity: Using functional programming—functions together with immutable state—makes asynchronous event-driven programming so much easier. Async programming means non-blocking and process isolation, and it forms the basis for the nice properties defined in the Reactive Manifesto. It encourages reactive programming, and it makes it less verbose and clumsy to do so. My company recently ran a survey of more than 2,800 Java developers that surfaced their attitudes and intentions around Java 8. That 83% viewed support of lambda expressions and virtual extension methods as the most interesting feature area in Java 8 is telling that Java developers have been wrestling with thorny areas like state and failure management, and have a strong appetite for new approaches that will make their lives easier.
Functional programming has a lot of really nice properties if it’s done the right way. It gives you code that you can trust, code that doesn’t lie, since it relies on stable values. It’s code that discourages side effects and where side effects are decoupled from state changes. The functional programming directions that Java 8 is introducing to the Java masses are very exciting, and we believe that a certain percentage of that market isn’t going to stop there. It’s going to open their eyes to some of the innovations in Scala, Erlang, Haskell, and libraries like Google Guava.
Jonas Bonér is a cofounder of Typesafe and creator of the Akka event-driven middleware project. Previously he was a core technical contributor at Terracotta, working on core JVM-level clustering technology, and at BEA, as part of the JRockit JVM team. Jonas has also been an active contributor to open-source projects, including the AspectWerkz AOP framework and the Eclipse AspectJ project.