visit
If you’re a Java developer, I’m sure that you have seen code similar to the featured image snippet above at least once. The code in the snippet above is an example of functional programming paradigm implementation in Java, which will filter and transform the
List<String>
in the request to another List<String>
.In this article, I will write about how to write code using Java’s API for functional programming. In the end, we will write our own stream API so we can understand how to implement a functional programming style in Java.To understand how functional programming works in Java, first we will need to look at the annotation included in Java 8 SDK,
@FunctionalInterface
. We can look at it on the .From the API documentation, we can see that the behaviors of a functional interface annotation in Java are:Interface
type.@FunctionalInterface
because the compiler will treat any interface meeting the definition of a functional interface as a functional interface.Let’s first create a model called
Person
.For the functional interface, we’ll create
PersonFunctionalInterface
class.Note that there are two methods in the interface, but since there is only one abstract method,
PersonFunctionalInterface
class is valid as a functional interface.But suppose we define more than one abstract method, like so:It will produce an error:Anonymous class
Let’s first learn about the anonymous class. Java says that:“Anonymous classes enable you to make your code more concise. They enable you to declare and instantiate a class at the same time. They are like local classes except that they do not have a name. Use them if you need to use a local class only once.”Basically, with an anonymous class, we don’t have to define a class that implements the interface we made. We can create a class without a name and store it in a variable.Let’s declare an anonymous class as an example.
What we’ve done here is we created an anonymous class with
PersonFunctionalInterface
type and anonClassExample
name.We override the
createPerson
abstract method so when we call the method, it will return a new Person object with a name.When we called
anonClassExample.createPerson(“Hello, World”)
, we basically just created a new Person object with “Hello, World” as its name.We can start creating the anonymous class of
PersonFunctionalinterface
for the functional interface we made.We’ve just implemented the functional interface!In the code above, we created three anonymous classes in different ways. Remember that the anonymous class has the behavior that we can create a functional interface with a lambda expression, method references, or constructor references.To make sure we created anonymous classes that behave the same, we assert every method in the interface.Java 8 has many built-in functional interface classes in the
java.util.function
package that we can see in .In this article, I will only explain four of the most commonly used functional interfaces, but if you’re interested in more, you can read it in the Java API documentation noted above.Consumer<T>
: A functional interface that accepts an object and returns nothing.Producer<T>
: A functional interface that accepts nothing and returns an object.Predicate<T>
: A functional interface that accepts an object and returns a boolean.Function<T, R>
: A functional interface that accepts an object and returns another object.Stream and optional API
Java’s Stream API uses functional interfaces a lot, as we can see in the code below.The
filter
method has a parameter Predicate<T>
functional interface. As we can see, the method accepts a String
and produce a boolean
.The
map
method uses Function<T, R>
as its parameter. It accepts a String and also returns String
.The
forEach
method in Stream and ifPresent
method in Optional accept Consumer<T>
, accepting a String
and not returning anything.Reactive library
Both of the most popular Java Reactive libraries, and , are based on Java 8 Streams API, which means they also use functional interfaces in their code.If we look at and , we can see many of their methods accept a functional interface.Constructor
We made two constructors, one constructor imitating the
Stream.of()
API and one constructor to convert List<T>
to SimpleStream<T>
.Filter
In this method, we accept
Predicate<T>
as a parameter since Predicate<T>
has an abstract parameter named test
that accepts an object and produces a boolean
.Let’s look at the test class, where we wrote:This means we wrote an anonymous class implementing
Predicate<T>
:So in the
SimpleStream<T>
class, we can see the filter method as:Map
In the map method, we accept
Function<T, R>
as its parameter, which means the map method will accept a functional interface that accepts an object and also produces an object.We wrote the following in the test classIt’s the same as creating an anonymous class implementing
Function<T, R>
:And in the
SimpleStream<T>
class, we can see it as this:The
forEach
method accepts Consumer<T>
as its parameter, meaning that it will accept an object and return nothing.We wrote the following in the test class:This translates to creating an anonymous class implementing
Consumer<T>
:In the
SimpleStream<T>
, we can see the forEach
method, as below:Previously published at //codecurated.com/blog/functional-programming-in-java-explained/