DEV Community

Cover image for The ultimate guide to Functional interfaces in Java
Mukund Madhav
Mukund Madhav

Posted on • Updated on • Originally published at mukundmadhav.com

The ultimate guide to Functional interfaces in Java

Functional interfaces in Java

We all have heard that Java Functional interfaces unleashed functional programming paradigm in Java.

That’s all cool but…what are these Functional interfaces?

Let’s try Oracle’s official documentation for the Functional interface:

Functional interfaces provide target types for lambda expressions and method references. Each functional interface has a single abstract method, called the functional method for that functional interface, to which the lambda expression’s parameter and return types are matched or adapted.

Oracle

Hm. That did not help much? Or did that answer a bit?

Either way, don’t fret.

We will dive deep into Functional interfaces. Additionally, we will explore the most commonly used built-in interfaces like predicate, function, supplier and consumer.

This is a bit long article, if short on time, skip to the TLDR at the end. (There’s a summarised infographic 😃)

Flipchart, Presentation, Powerpoint, Office, Work, Draw

First question, what are Functional interfaces?

Simple, they are interfaces in Java that follow the following criteria:

  • Is an interface – duh! 🙆‍♂️
  • Has just one abstract method

The good thing to note here would be that, since Java 8, interfaces can have default methods So, having multiple or no default methods have no effect whatsoever on the interface’s criteria for being a functional interface.

That’s clear, I hope.

Now onto @FunctionalInterface.

Remember the two rules we talked about Functional interfaces?

The @FunctionalInterface instructs the compiler to treat and validate the interface as a functional interface. And hence, if the compiler finds out that the criteria for a functional interface is not met while the annotation @FunctionalInterface is used, it will throw an appropriate error message.

However, usage of the annotation is completely optional.

How Java 8 made these functional interfaces cooler?

Before Java 8, to define a functional interface we used to have to write verbose looking anonymous classes.

Here’s a snippet of how that used to look:

Yeah, I know. 🤮

But with the introduction of lambdas ( which is just a short form to represent a specific type of anonymous class → Functional interfaces) here’s how the code would look

Pretty neat, eh?

Now, that we know what functional interfaces are, let’s look at some amazing in-built JDK 8 ones.

Before we go…

Before we go any further, let’s quickly look at lambdas so that everything makes much more sense later.

Lambdas are

  • Another way to represnet functional interface instead of anonmoys function
  • The common syntax looks something like

ReturnType lambdaName = parameter -> parameter + ” do something with parameter”;

lambdaName is the name of lambda. And, the parameter is well, parameter to the lambda function.

For more on lambda, I’d recommend checking out this lambda guide. Else, let’s move to functional interfaces.

Exploring java.util.function package

Tool, Pliers, Screwdriver, Construction, Equipment

This package contains several nifty functional interfaces that forms the basis for functional programming in Java.

These functional interfaces have commonly used applications. Hence, it makes senses to use them.

Most of the times, these are syntactical sugars that makes coding a little bit more pleasant thanks to functional approach to things.

Let’s begin with most simple of them.

Java Predicate

What is a Java Predicate?

Java Predicate is a built-in functional interface that accepts a single argument and returns a “boolean” (not Boolean) value result.

Did not get it?

Let me show with an example:

Suppose you want to check if a number is greater than 0. Here’s how a predicate would look like:

Predicate<Integer> checkIfPositive = num -> (num > 0);
System.out.println(checkIfPositive.test(2)); // Output: true
Enter fullscreen mode Exit fullscreen mode

When this predicate is called at line 2, it will return true/false

What is this test method that is being called in predicate? Let’s quickly glance over some poplar predicate method then it will make better sense.

Popular Predicate methods

  • test (the single abstract method for Predicate)

Remember how we discussed functional methods can have a single abstract method? Well, “test” is that method for Predicate.

It evaluates the results and returns true or false. Like in the initial example it will print true.

  • and

It represents the logical AND (like && in Java) for predicate outputs.

So, since predicate return true and false, joining them with “and” will feel like adding && conditions.

Predicate<Integer> checkIfPositive = num -> (num > 0);
Predicate<Integer> checkIfSmallerThan100 = num -> (num < 100);

System.out.println(checkIfPositive.and(checkIfSmallerThan100).test(60)); // Output: true
Enter fullscreen mode Exit fullscreen mode

In the above example, the “and” operator will logically work as ” checkIfPositive AND checkIfSmallerThan100″

This particular case might be helpful in validating if valid age

  • or

It represents the logical OR operator (like || in Java) for predicate outputs.

Let’s look below:

Predicate<Integer> greaterThan18 = num -> (num > 18);
Predicate<Integer> lessThan64 = num -> (num < 64); 

System.out.println(lessThan64.or(greaterThan18).test(21)); // Output: true
Enter fullscreen mode Exit fullscreen mode

In the above example, the “or” operator will logically work as ” lessThan64 OR greaterThan18″

But why would we even use them?

Common uses for Predicate

List, Icon, Symbol, Paper, Sign, Flat, Note, Form, Mark

  • Streams allMatch and anyMatch

Predicate gets even powerful with Java 8’s streams.

Suppose you are getting list of Persons from a list somewhere and you need to verify if all the Person have required access to continue for some resource.

Here’s how that will look with Predicate:

class Person { // Point 1 

        //assume getters and setters
        private Integer pkId;
        private String name; 
        private String accessLevel;

        public String getAccessLevel() {
                return this.accessLevel;
        }
}

public class MainApp {

   public static void main(String[] args) {

      List<Person> allPeople = getListOfPersons);
      Predicate<Person> checkAccessLevel = p ->  p.getAccessLevel().equals("ADMIN");
      boolean toAllow = list.stream().allMatch(checkAccessLevel); // Point 2
      if(alltoAllow) 
        System.out.println("Allowed");
      else
        System.out.println("Denied access");
    }

}
Enter fullscreen mode Exit fullscreen mode

Point 1: Let this dummy Person object serve as our model. Note, that we are assuming that the private variables have properly named getters and setters

Point 2: In combination with streams, Predicate help us avoid boilerplate code to iterate through each object and do the string comparison.

  • Validation pattern

Detective, Searching, Man, Search, Magnifying

There’s a very innovative validator pattern implementation at Dzone that clearly explains the validation pattern.

Here’s the cookie cutter version:

Suppose there are several serious of validation you need to do at the backend(most commonly done for forms).

In that case instead of writing code like this:

Snippet from DZone

We can move to writing validations like this:

Snippet from DZone

Now what’s the profit?

  1. The validations are legible and there’s a reduction in redundant verbose code
  2. We can keep on dynamically adding more conditions and they would still be understandable, thanks to, separation done by “and”/”or” methods

If you are still here, congratulations! Now let’s enter Functions. Not that kind, the interfaces kind.

Sidenote:

Similar to Predicate, there are BiPredicate.

They, like the name implies, accept two instead of one parameter and follow all the other characteristics of Predicate.

That is all for this post. We'll cover more popular interfaces in the next post.

Happy coding 😃

Top comments (0)