In mathematical logic, a predicate is commonly understood to be a Boolean-valued function P: X→ {true, false}, called the predicate on X.
Informally, a predicate is a statement that may be true or false depending on the values of its variables. It can be thought of as an operator or function that returns a value that is either true or false. For example, predicates are sometimes used to indicate set membership: when talking about sets, it is sometimes inconvenient or impossible to describe a set by listing all of its elements. Thus, a predicate P(x) will be true or false, depending on whether x belongs to a set. [Ref: WikiPedia (https://en.wikipedia.org/wiki/Predicate_(mathematical_logic)]
In java 8, predicate is an functional interface java.util.function.Predicate<T> which defines an abstract method named test, that accepts an object of generic type T and returns a boolean. Predicate can be used as assignment target for a lambda expression or method reference.
Example:
package com.manishsanger.Predicate;
public class Vehicle {
private String type;
private Integer displacement;
public Vehicle(String type, Integer displacement) {
this.type = type;
this.displacement = displacement;
}
@Override
public String toString() {
return "Vehicle - Type:" + this.getType() + ", Displacement:" + this.getDisplacement() +"cc";
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Integer getDisplacement() {
return displacement;
}
public void setDisplacement(Integer displacement) {
this.displacement = displacement;
}
}
If we need to get the vehicle whose displacement is more that 1500 cc, we can write a predicate for it as below:
public class VehiclePredicate {
public static Predicate<Vehicle> isDisplacementAbove1500() {
return vehicle -> vehicle.getDisplacement() >= 1500;
}
}
We can user this predicate in filter(), to filter list of vehicle by condition in the predicate.
package com.manishsanger.Predicate;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class Example {
public static void main(String[] args) {
List<Vehicle> vehicles = Arrays.asList(
new Vehicle("SUV", 2200),
new Vehicle("SUV", 1800),
new Vehicle("SEDAN", 1600),
new Vehicle("HATCHBACK", 1400),
new Vehicle("SUV", 2800)
);
//Using default filter() method, using stream and lambda expression.
//return all Vehicles those have displacement more than 1500
System.out.println("All vehicles those have displacement more than 1500, Using default filter() method.");
vehicles.stream().filter(vehicle -> {
return vehicle.getDisplacement() >= 1500;
}).collect(Collectors.toList()).forEach(System.out::println);
//return all Vehicles those have displacement more than 1500
System.out.println("All SUV those have displacement more than 1500, Using default filter() method.");
vehicles.stream().filter(vehicle -> {
return vehicle.getType().equals("SUV") && vehicle.getDisplacement() >= 1500;
}).collect(Collectors.toList()).forEach(System.out::println);
}
}
Following will be the output:
All vehicles those have displacement more than 1500, Using default filter() method.
Vehicle - Type:SUV, Displacement:2200cc
Vehicle - Type:SUV, Displacement:1800cc
Vehicle - Type:SEDAN, Displacement:1600cc
Vehicle - Type:SUV, Displacement:2800cc
All SUV those have displacement more than 1500, Using default filter() method.
Vehicle - Type:SUV, Displacement:2200cc
Vehicle - Type:SUV, Displacement:1800cc
Vehicle - Type:SUV, Displacement:2800cc
We can also define our own custom filter method(), Now add a filterVehicles() method in VehiclePredicate class.
public static List<Vehicle> filterVehicles(List vehicles, Predicate<Vehicle> predicate) {
return vehicles.stream().filter(predicate).collect(Collectors.toList());
}
Add following code to Main class, to filter data using custom Predicate filter:
//Using custom filter method and java 8 lambda
System.out.println("\nAll vehicles those have displacement more than 1500, Using default custom filter method.");
VehiclePredicate.filterVehicles(vehicles, vehicle -> {
return vehicle.getDisplacement() >= 1500;
}).forEach(System.out::println);
Here is the output:
All vehicles those have displacement more than 1500, Using default custom filter method.
Vehicle - Type:SUV, Displacement:2200cc
Vehicle - Type:SUV, Displacement:1800cc
Vehicle - Type:SEDAN, Displacement:1600cc
Vehicle - Type:SUV, Displacement:2800cc
Here is how you can filter the list without lambda expression:
//Using custom filter method and without lambda
System.out.println("\nAll vehicles those have displacement more than 1500, Using default custom filter method without lambda.");
VehiclePredicate.filterVehicles(vehicles, VehiclePredicate.isDisplacementAbove1500()).forEach(System.out::println);
Here is the output, for the above block of code:
All vehicles those have displacement more than 1500, Using default custom filter method.
Vehicle - Type:SUV, Displacement:2200cc
Vehicle - Type:SUV, Displacement:1800cc
Vehicle - Type:SEDAN, Displacement:1600cc
Vehicle - Type:SUV, Displacement:2800cc
Java 8 Predicate Methods
Let’s now go through the methods available for Predicate:
1. Default Predicate and (Predicate other)
It returns a composed predicate that represents a logical AND of two predicates.
To understand this let’s add another predicate in the VehiclePredicates class:
public static Predicate<Vehicle> isTypeSUV() {
return vehicle -> vehicle.getType().equals("SUV");
}
Now we can apply and() and or() function if we want to predicate for Vehicle of type SUV and displacement more than 1500 cc.
Here is the code for Main method:
//Multiple filter with AND logical operator
System.out.println("\nAll SUV those have displacement more than 1500, Using custom Predicate filter without lambda.");
VehiclePredicate.filterVehicles(vehicles, VehiclePredicate.isDisplacementAbove1500().and(VehiclePredicate.isTypeSUV())).forEach(System.out::println);
//Multiple filter with OR logical operator
System.out.println("\nAll Vehicle those have displacement more than 1500 or SUV, Using custom Predicate filter without lambda.");
VehiclePredicate.filterVehicles(vehicles, VehiclePredicate.isDisplacementAbove1500().or(VehiclePredicate.isTypeSUV())).forEach(System.out::println);
Here is the output:
All SUV those have displacement more than 1500, Using custom Predicate filter without lambda.
Vehicle - Type:SUV, Displacement:2200cc
Vehicle - Type:SUV, Displacement:1800cc
Vehicle - Type:SUV, Displacement:2800cc
All Vehicle those have displacement more than 1500 or SUV, Using custom Predicate filter without lambda.
Vehicle - Type:SUV, Displacement:2200cc
Vehicle - Type:SUV, Displacement:1800cc
Vehicle - Type:SEDAN, Displacement:1600cc
Vehicle - Type:SUV, Displacement:2800cc
2. Default Predicate negate()
It return an predicate that represents logical NOT operator.
For example all Vehicles other than SUV:
//default negate(), Logical NOT operator. All vehicles other than SUV
System.out.println("\nAll vehicles other than SUV, using negate()");
VehiclePredicate.filterVehicles(vehicles, VehiclePredicate.isTypeSUV().negate()).forEach(System.out::println);
Here is the output:
All vehicles other than SUV, using negate()
Vehicle - Type:SEDAN, Displacement:1600cc
Vehicle - Type:HATCHBACK, Displacement:1400cc
3. Boolean test (T t)
Predicate test evaluates this predicate on the given argument.
For example we can pass an Vehicle object to check if this predicate return true or false:
Add the following code in main method:
//boolean test(T t) predicate
System.out.println("\nboolean test predicate");
Vehicle testVehicle = new Vehicle("SUV", 1000);
System.out.println(VehiclePredicate.isTypeSUV().test(testVehicle));
System.out.println(VehiclePredicate.isDisplacementAbove1500().test(testVehicle));
Here is the output:
boolean test(T t) predicate
true
false
4. static Predicate isEqual(Object targetRef)
Returns a predicate that tests if two arguments are equal according to Objects.equals() method.
Let’s say we overridden equals() method for Vehicle class
@Override
public boolean equals(Object obj) {
Vehicle vehicle = (Vehicle) obj;
if (this.getType().equals(vehicle.getType()) && this.getDisplacement().equals(vehicle.getDisplacement())) {
return true;
}
return false;
}
Now let’s say we have a Vehicle which has standard type & displacement. Then we can get a Predicate, that will test if the given Vehicle is standard or not.
//static Predicate isEqual(Object targetRef)
System.out.println("\nstatic Predicate isEqual(Object targetRef)");
Predicate standardVehiclePredicate = Predicate.isEqual(new Vehicle("SUV", 1800));
System.out.println(standardVehiclePredicate.test(new Vehicle("SUV", 1800)));
System.out.println(standardVehiclePredicate.test(new Vehicle("SUV", 1500)));
Here is the output:
static Predicate isEqual(Object targetRef)
true
false