3 min read

Java Interview Questions (series) - Common Functional Interfaces

Java Interview Questions (series) - Common Functional Interfaces
80% of the time you use 20% of the @FunctionalInterfaces ๐Ÿ‘‹

Brief

๐Ÿค” ย In a previous post, we spoke about the @FunctionalInterface feature coming with Java 8.

We understood:

๐Ÿ”น What is it used for?

๐Ÿ”น What is it made of?

๐Ÿ”น How you can create your own?

Java developers also created some out of the box functional interfaces to make our lives easier. ๐Ÿ’ฏ

In this post, we'll go through the most used ones, what are they used for and how to use them on your particular use-case. ๐Ÿš€

Implementation

๐Ÿ”ต ย  Predicate

Functional interface whose abstract method accepts a single element and returns a boolean.

@FunctionalInterface
public interface Predicate<T> {
    boolean test(T input);
}

Remembering from the previous post on functional interfaces, we need to provide an implementation for the test abstract method.

๐Ÿ”ธ ย  Example

Let's create a predicate which determines if a given integer is even or odd.

Predicate<Integer> isEvenPredicate = input -> input%2 == 0;  // provide implementation through a lambda expression

To use it, you only need to call its test method.

boolean res1 = isEvenPredicate.test(4);   // will return true

boolean res2 = isEvenPredicate.test(5);   // will return false;


๐Ÿ”ต ย  Consumer

Functional interface whose abstract method accepts a single element and returns void.

@FunctionalInterface
public interface Consumer<T> {
    void accept(T input);
}

๐Ÿ”ธ ย  Example

Let's say you want to print the element on the console.

Consumer<Integer> loggingConsumer = input -> System.out.println(input);  // provide implementation through a lambda expression

And then, to apply it, you'll call the accept method.

loggingConsumer.accept(2);  // will print to the console: "2"


๐Ÿ”ต ย  Supplier

Functional interface whose abstract method doesn't have any input parameters but returns a value.

@FunctionalInterface
public interface Supplier<T> {
    T get();
}

๐Ÿ”ธ ย  Example

A use-case for this one might be to generate a random number.

Supplier<Double> randomSupplier = () -> Math.random();   // provide implementation through a lambda expression

To use it, you'll use the get method.

Double random = randomSupplier.get();


๐Ÿ”ต ย  Function

Functional interface whose abstract method accepts a single element as an input and also returns a value.

@FunctionalInterface
public interface Function<T, U> {
    U apply(T input);
}

In other words, it's a combination of Consumer and Supplier.

This is the one you should use when you want to change the state of the elements, or generate a new type of object based on the input.

๐Ÿ”ธ ย  Example

You may have a User object with a name property.

Given a string provided as input for name, with Function, you can create a User with that particular name.

public class User {
    private String name;

    public User(String name) {
        this.name = name;
    }
}
User.java
Function<String, User> userFunction = input -> new User(input); // provide implementation through a lambda expression

User user = userFunction.apply("John Doe"); // generates a user with "John Doe" for name.


Bonus

Each of these functional interfaces that we just discussed, also have a correspondent which can accept 2 input parameters of different types.

Except the Supplier one, of course, as it can't receive any parameter.

๐Ÿ”น ย  BiConsumer<T,U> - accepts one T parameter and one U parameter and returns void.

@FunctionalInterface
public interface BiConsumer<T, U> {
    void accept(T t, U u);
}
BiConsumer.java
BiConsumer<Integer, String> loggingConsumer = (input1, input2) -> System.out.println(input1 + input2);

loggingConsumer.accept(12, "apples"); // will print to the console: "12 apples"
Example

๐Ÿ”น ย  BiFunction<T,U,R> - accepts one T parameter and one U parameter and returns a R parameter.

@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T t, U u);
}
BiFunction.java
public class User {
    private String name;
    private Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
}
User.java
Function<String, Integer, User> userFunction = (name, age) -> new User(name, age); // provide implementation through a lambda expression

User user = userFunction.apply("John Doe", 23); // generates a user with "John Doe" for name and "23" for age.
Example

๐Ÿ”น ย  BiPredicate<T,U> - accepts one T parameter and one U parameter and returns a boolean.

@FunctionalInterface
public interface BiPredicate<T, U> {
    boolean test(T t, U u);
}
BiPredicate<Integer, Integer> comparePredicate = (number1, number2) -> number1 >= number2;

comparePredicate.test(1,2); // returns false

comparePredicate.test(3,1); // returns true
Example


๐Ÿ’ก
Don't miss out on more posts like this! Susbcribe to our free newsletter!
๐Ÿ’ก
Currently I am working on a Java Interview e-book designed to successfully get you through any Java technical interview you may take.
Stay tuned! ๐Ÿš€