Learn Java Predicate, Consumer, Function, and Supplier (Functional Interfaces) with Example
Java is Object Oriented Programming language, being object-oriented is not bad, but it brings a lot of verbosity to the program.Java 8 introduced new libraries and programming styles, for example, functional interfaces, lambda expressions, and streams. These bring functional-style programming to the object-oriented programming capabilities of Java. Java Functional Interface and Lambda Expression help us write smaller and cleaner code by removing much boilerplate code.
A functional interface contains only a single abstract method and can include default and static methods that do have an implementation and a single unimplemented method.
Here we will discuss Predicate, Consumer, Function, and Supplier.
1. Predicate Interface
The Predicate is a functional interface defined in java. util. Function package, which accepts an argument and returns a boolean. This is mainly used to filter data from a Java Stream. The filter method of a stream accepts a predicate to filter the data and returns a new stream satisfying the predicate.
The predicate is a functional interface that means we can pass it in lambda expressions wherever a predicate is expected. For example, one such method is the filter() method from the Stream API.
Here we are showing one example program,
- Find the users whose age is greater than 35.
- Find the users whose name starts with 'B'.
- Find the users whose name starts with 'A' or 'B'.
Example - Filtering Streams with Predicate:
import java.util.ArrayList;import java.util.List;import java.util.function.Predicate;import java.util.stream.Collectors;
// When we pass the predicate in the Stream.filter() method,// it returns a new stream with matching items only, // that we can collect in a new List.
public class DemoApplication {
// Predicate to find all users whose age is more than 35 public static Predicate<User> isPro() { return p -> p.getAge() > 35; }
// Predicate to find all users whose name starts with B public static Predicate<User> nameStartsWithB() { return p -> p.getName().startsWith("B"); }
// Predicate to find all users whose name starts with B or A public static Predicate<User> nameStartsWithBorA() { return p -> p.getName().startsWith("B") || p.getName().startsWith("A"); }
//Test public static void main(String[] args) {
List<User> userList = new ArrayList<User>(); userList.add(new User("1", "Alpha", 60)); userList.add(new User("2", "Beta", 50)); userList.add(new User("3", "Gama", 40)); userList.add(new User("4", "Becca", 30)); userList.add(new User("5", "Tesla", 20)); userList.add(new User("6", "Noob", 10));
System.out.println("All users ="); System.out.println(userList);
List<User> above35 = userList.stream(). filter(isPro()) .collect(Collectors.<User>toList()); System.out.println("Users whose age above 35="); System.out.println(above35);
List<User> nameStartsWithB = userList.stream(). filter(nameStartsWithB()) .collect(Collectors.<User>toList()); System.out.println("Users whose name starts with B="); System.out.println(nameStartsWithB);
List<User> nameStartsWithBorA = userList.stream(). filter(nameStartsWithBorA()) .collect(Collectors.<User>toList()); System.out.println("Users whose name starts with B or A="); System.out.println(nameStartsWithBorA);
}
}
// User POJOclass User {
private String id; private String name; private int age;
public User(String id, String name, int age) { this.id = id; this.name = name; this.age = age; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override public String toString() { return "User [age=" + age + ", id=" + id + ", name=" + name + "]"; }}
Output:
All users =
[User [age=60, id=1, name=Alpha], User [age=50, id=2, name=Beta], User [age=40, id=3, name=Gama], User [age=30, id=4, name=Becca], User [age=20, id=5, name=Tesla], User [age=10, id=6, name=Noob]]
Users whose age above 35=
[User [age=60, id=1, name=Alpha], User [age=50, id=2, name=Beta], User [age=40, id=3, name=Gama]]
Users whose name starts with B=
[User [age=50, id=2, name=Beta], User [age=30, id=4, name=Becca]]
Users whose name starts with B or A=
[User [age=60, id=1, name=Alpha], User [age=50, id=2, name=Beta], User [age=30, id=4, name=Becca]]
2. Consumer Interface
The Consumer is a functional interface defined in java. util. Function package, which accepts a single input argument and returns no result. Unlike most other functional interfaces, the Consumer is expected to operate via side effects.
Consumer accept() and andThen() method example
- accept() method is the primary abstract method of the Consumer functional interface. accept() method takes as input the type T and returns no value.
- andThen() method is a helper tool to join consumers. Instead of passing the input to all of them in a loop. We use andThen when we want to chain the logic of two Consumers.
import java.util.ArrayList;import java.util.List;import java.util.function.Consumer;
public class DemoApplication {
// Test public static void main(String[] args) {
// Dummy users List<User> userList = new ArrayList<User>(); userList.add(new User("1", "Alpha", 60)); userList.add(new User("2", "Beta", 50)); userList.add(new User("3", "Gama", 40)); userList.add(new User("4", "Becca", 30)); userList.add(new User("5", "Tesla", 20)); userList.add(new User("6", "Noob", 10));
// Consumer accept() method example // Consumer to find print all users Consumer<List<User>> consumerUser = s -> System.out.println(s); consumerUser.accept(userList);
// Consumer forEach() example // Creating Consumer for user object // which will be used in forEach method of list Consumer<User> consumerForUser = s -> System.out.println(s); userList.forEach(consumerForUser);
// Consumer andThen() method example Consumer<User> userA = x -> System.out.println(x.getName() .toLowerCase()); Consumer<User> userB = y -> System.out.println(y.getName() .toUpperCase()); Consumer<User> result = userA.andThen(userB);
User user = new User("1", "Alpha", 60); result.accept(user); }
}
// User POJOclass User {
private String id; private String name; private int age;
public User(String id, String name, int age) { this.id = id; this.name = name; this.age = age; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override public String toString() { return "User [age=" + age + ", id=" + id + ", name=" + name + "]"; }}
Output:
[User [age=60, id=1, name=Alpha], User [age=50, id=2, name=Beta], User [age=40, id=3, name=Gama], User [age=30, id=4, name=Becca], User [age=20, id=5, name=Tesla], User [age=10, id=6, name=Noob]]
User [age=60, id=1, name=Alpha]
User [age=50, id=2, name=Beta]
User [age=40, id=3, name=Gama]
User [age=30, id=4, name=Becca]
User [age=20, id=5, name=Tesla]
User [age=10, id=6, name=Noob]
alpha
ALPHA
3. Function Interface
The Function is a functional interface defined in java. util. Function package. The primary purpose for which Function<T, R> has been created is for mapping scenarios i.e when an object of a type is taken as input and it is converted to another type. Common usage of Function is in streams where-in the map function of a stream accepts an instance of Function to convert the stream of one type to a stream of another type.
Function example - Find the size of the user list.
import java.util.ArrayList;import java.util.List;import java.util.function.Function;
public class DemoApplication {
// Test public static void main(String[] args) {
// Dummy users List<User> userList = new ArrayList<User>(); userList.add(new User("1", "Alpha", 60)); userList.add(new User("2", "Beta", 50)); userList.add(new User("3", "Gama", 40)); userList.add(new User("4", "Becca", 30)); userList.add(new User("5", "Tesla", 20)); userList.add(new User("6", "Noob", 10));
// Function interface example to find the size of user list. Function<List<User>, Integer> func = x -> x.size();
Integer size = func.apply(userList); // 6
System.out.println(size);
}
}
// User POJOclass User {
private String id; private String name; private int age;
public User(String id, String name, int age) { this.id = id; this.name = name; this.age = age; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }}
4. Supplier Interface
The Supplier is a functional interface defined in java. util. Function package. The Supplier interface takes no argument and returns a result. As this is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference. The Supplier has only one get() method and has no default method. In the below example, we created the Supplier object which will be used to supply a new User object.
Supplier example
import java.util.function.Supplier;
// create Supplier object which will // be used to supply new User object.public class DemoApplication {
// Test public static void main(String[] args) {
Supplier userSupplier = () -> new User("1", "Alpha", 60); User user = (User) userSupplier.get(); System.out.println(user);
}
}
// User POJOclass User {
private String id; private String name; private int age;
public User(String id, String name, int age) { this.id = id; this.name = name; this.age = age; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override public String toString() { return "User [age=" + age + ", id=" + id + ", name=" + name + "]"; }}
Output:
User [age=60, id=1, name=Alpha]