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.
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
.
🔹 BiFunction<T,U,R>
- accepts one T
parameter and one U
parameter and returns a R
parameter.
🔹 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);
}
Stay tuned! 🚀