Fundamentals of Functional Programming in Java

Rajat Gogna
Geek Culture
Published in
4 min readApr 20, 2021

--

Basics of Java 8 Lambdas!

This blog aims to explain the basics of functional programming, using Java 8 lambdas. The blog assumes you have no prior knowledge of the functional programming paradigm but have basic knowledge of Object-Oriented Programming.

What is Functional Programming.

Functional programming is nothing but a style of programming, that promotes pure functions. By pure function, I mean a piece of code that takes some input, performs computations, and gives the desired output. It doesn’t have any “side-effects” or tasks, like printing or manipulating variables outside its own scope. These functions are first-class functions, i.e., they can simply be used as values, which can be passed as arguments/parameters to other functions.

This type of programming was not supported in Java, until Java 8. Until Java 8, all the blocks of code belonged to a class. So, in order to perform even a simple function like printing a greeting message, we would have to write a separate class to implement this logic. We could not have a simple function in isolation which would implement this logic. This changed in Java 8, with the introduction of lambda expressions.

Why do we need functional programming, when we can already do everything we want using mainstream Object Oriented Programming?

Functional programming helps in writing clear and concise code, which is easily maintainable (in some scenarios). It allows easier use of APIs and libraries, along with enabling ways to leverage parallel processing.

Let’s try and understand the advantages offered by lambdas, by comparing programming approaches followed in Java 7 and 8. We will see how an action can be performed in Java 7 vs Java 8.

The java 7 way — Simple OOP

In order to implement a behaviour in the object oriented programming paradigm, we would have a setup that looks like the one shown below:

A class that performs the activity declared in the interface will now have to create or retrieve the THING (instance of the class whose behaviour is desired), and pass that as a parameter to it’s method, in order to perform the activity. See the code snippets below:

What did we do here?

  1. Created an interface “MakeBeverage”. This is the activity that needs to be performed. It gives a blueprint that the behaviour of the activity should be defined in the method named “make” .
  2. Created two entities implementing the interface “MakeBeverage”. These entities had their own behaviour for the activity, and thus, their behaviour were defined in the implementation of their respective “make” methods. The code inside this “make” method is their ACTION.
  3. Created an executor class called “BeverageMaker”, which had a method, expecting the activity as a parameter. This method performed the action, based on the instance of the entity implementing the activity, passed as the parameter.

The java 8 way — Lambda Expressions

Java 8 introduced lambda expressions, which enabled us to write concise code. This is done by eliminating the need to create an implementation of the activity (interface). Instead of creating different entities with different behavior, we can simply store the “Action” of the entity in a variable, and pass that as a parameter in the executor class. See, the code below:

With the executor class “BeverageMakerWithLambda”, we did not need the entities implementing the interface “MakeBeverage”. We simply declared the “Action”, i.e., the code simulating the behaviour of each entity class as a variable. The type of the variable, being the activity interface “MakeBeverage”.

The difference between the Java 7 approach and the Java 8 approach is, that, instead of implementing an entire class for performing a standalone action, we simply implemented a function.

Type Inferencing

Java 8 is automatically able to deduce the return type of Lambda Expressions, and also the type of the parameters being passed to the expression. This is called Type Inferencing. This is performed by the java compiler.

Automatically!! How?

Java has named the interfaces used for creating lambda functions, Functional Interfaces.

  • They can have just a single method declared inside them.
  • When used as a type of the variable which is being used to store a lambda expression, the java compiler checks the return type and argument type, of the abstract method inside the interface, and expects the lambda expression to comply with the same.

In our example, the MakeBeverage interface acts as the functional interface.

Do we create a functional interface for every lambda we want to implement?

There is no need to create a new Functional Interface to implement your lambda logic. Existing Java interfaces which have only one method can be used for this purpose. Let us see this with an example of the Runnable Interface, which has only one method.

In the above code snippet, the Runnable Interface has been implemented using anonymous inner class approach, and the lambda approach. It can be clearly seen how clear and concise the code is in the case of lambdas.

Java provides an out of the box package of functional interfaces, which can be used for implementing lambda functions, based on the input parameter and return type requirements of your code. Refer https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html for package details.

This marks the end of this blog. Java 8 lambda is a huge topic, with great implementations to reduce verbosity of java code. Implementation of Java stream using lambda is a very interesting topic, and one I shall cover in future blogs.

Practice is the only option 👍

Checkout my GitHub for the code of this blog, and other projects.

--

--