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! ๐