Codementor Events

Java Interview Questions (series) - Common Functional Interfaces

Published Oct 04, 2022
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. πŸš€

Check out more posts like this on new-spike.net! πŸš€

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"

Check out more posts like this on new-spike.net! πŸš€

πŸ”΅ Β  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.

Check out more posts like this on new-spike.net! πŸš€

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

Check out more posts like this on new-spike.net! πŸš€

Discover and read more posts from Andrei Saizu
get started