Get a Sight of Functional Programming in Java
Functional programming is a programming paradigm where programs are created by applying and combining functions. This enables us to write programs in a declarative and composable way, where small functions are combined in a modular way. Rightly, functional programming is all about expressions introduced in Java 8. Functional techniques improve java programming by making us think functionally about cording tasks.
This article may help you become familiar with functional programming in a simple and easy-to-understand manner.
In Java 8, a new feature was introduced called lambdas. Lambdas represent the implementation of a functional interface.
Functional Interfaces
A functional interface is an interface that has only one abstract method. The following code snippet shows a simple interface called GreetingMessage
. The interface has a single abstract method called greet which takes one argument of type string called name. The annotation functionalInterface
has been added above the name of the interface to show that it conforms to the rules of a functional interface.
Implement the functional interface in another class:
Here inside the main method, a new instance of GreetingMessage
called gm
is equal to the new GreetinMessage
instance. we override the greeting method as GreetingMessage
has an abstract method with no implementation. we have to add our own implementation every time we create a new instance of GreetingMessage
. This is also known as an anonymous inner class.
The method can be called by gm.greet("name")
, passing a name. This outputs hello with the name given.
That is all the functional interface is. It allows Java Programmers to pass the code around as data. The code to implement our functional interface is quite long and messy considering that all it does is provide one new line of functionality. Lambda is introduced to improve this.
Implementing lambdas in java
Lambdas provide a short and simple way to implement a functional interface in Java. They are now commonly used features in the Java language.
Here there is a functional interface called GreetingMessage
which has a single abstract method called greet
. In the Main
class a new GreetingMessage
an instance is implemented using an anonymous inner class. The GreetingMessage
and print out hello followed by the name passed in.
Instead of using all this boilerplate code, we can use lambda instead to make the code shorter and simpler.
We also can just put the name in here. Here we get the same outputs for both implementations. we use the lambda with less code. we didn’t need to create a new greeting message or write out the whole body of the method again.
For example, let’s take functional interface MessagePrinter
which has a single abstract method, called printMessage
which takes no arguments.
In main
method of the Main
class,
This outputs our message. So lambdas are a quick and simple way of implementing functional interfaces, they look quite different to anonymous inner classes, but the logic is the same and it is easy to understand when we are used to reading the syntax.
Using method references in java
Method reference is shortened way of writing a certain type of lambda expression. If you have a lambda expression that passes in a variable and then calls a method on that variable, you can replace it with a method reference.
In this example, there is a class called Square
. This class has one private field of type int
called sideLength
and public calculate area method, which calculates the area by multiplying sideLength
by sideLength
. The constructor of the Square
class specifies that we have to pass in an int
for the sideLengt
value.
A functional interface called shapes is there. This has a single abstract method called get area.
In main
method of the Main
class,
When run the program shows the area as 16(4*4). Let's use a method reference to make this code shorter and simpler. we can do this because we are using lambda for calling a single method on the square object that we are passing in.
This also prints out the area of the square is 16. This is shorter and simple than the lambda.
Understanding streams in Java
Streams provide a clean and simple way to iterate over a collection in Java. Instead of using a forEach
loop, streams allow functional programming techniques to be used. These streams are not to be confused with input and output streams which are something completely different.
For example, the forEach loop iterates over a collection of books. If the author of the book’s name begins with the letter J, then the two-string method of the book is called and printed to the terminal. Here it uses external iteration.
Issues of External Iteration:
- Hard to write parallel iterations
- Requires a lot of boilerplate codes to write.
- Difficult to read the meaning.
- There is no much abstraction between the code and the implementation.
Streams, which are introduced in Java 8, provide solutions to these issues. Streams work differently to forLoops
. They use internal iteration instead of external iteration.
we can rewrite forEach loop to use a stream to iterate over the collection of books.
The first method called stream()
returns a stream object. This is an interface that contains a sequence of elements from the collection we called the method on. It contains book objects from the books list.
Then the filter()
method, Streams have two different types of methods, lazy methods, and eager methods. Here we are using the filter()
method as an example of lazy method. The only thing this method does is checks if the author begins with J, and if it does, then it adds it to the stream.
Finally, there is the forEach
method, which is an eager method. This prints out all of the objects in the stream. So instead of creating an iterator object, which a forEach
loop does, it creates a stream object. For each item, if the author begins with “J”, then it adds that item to the stream. It doesn’t print out the book straightway, instead, it waits till the end when it has a stream of all the books whose author begins with “J”. Then it prints out that stream.
If we want to add more filters, we would change them to the end of the first one.
This is much simpler to read than forEach
loop, where we need to add a new nested if statement for each condition. It is also more computationally efficient to use this approach.
Implementing streams in java
Book.java
Library.java
Implementing parallel streams
Here the only thing that needs to change in the code is to change the stream method to the parallel stream method.
Here I have included code-embedded which I used in understanding each scenario for your reference.
Thanks for reading, follow me to see more articles..