How to Compare List Objects in Java 7 vs. Java 8
In this blast from the not-too-distant past, we compare how Java 8's Stream API changed how you can compare List objects.
Join the DZone community and get the full member experience.
Join For FreeComparing the content of List
s against some condition is a common use case to handle in many business scenarios. This comparison can be broadly classified as:
- Comparing each element of a List against some condition. As an example, you have a List of Employee Objects and you need to check that all your Employees are above 18.
- One or more elements from one List match(es) the elements of another List.
- All elements of a List exist in another List.
Now, developing these use cases is very easy in Java 7 with relatively few lines of code. The following is an example where we are comparing two Lists in Java 7 and checking if any element from List 1 exists in List 2.
package com.tuturself;
import java.util.Arrays;
import java.util.List;
public class ListCompare {
public static void main(String[] args) {
List < Integer > aList = Arrays.asList(new Integer[] {
1,
3,
5,
6,
8
});
List < Integer > bList = Arrays.asList(new Integer[] {
10,
89,
8,
9
});
for (Integer i: aList) {
if (bList.contains(i)) {
System.out.println("Match Found " + i);
break;
}
}
}
}
Now let us develop all the above use cases in Java 8. The Java 8 Stream API provides three methods allMatch
, anyMatch
, and noneMatch
, which can be applied to a stream object that matches the given Predicate and then returns a boolean value. It is recommended to check the following articles if you are not familiar with the Stream API.
What Is ‘Matching’ in the Context of Streams?
Given a stream of objects, many-a-times, we need to check whether objects in the given stream match some specific criteria. Instead of writing logic for iterating over the stream elements and checking whether each object matches the criteria, Java 8 Streams allow declarative matching of objects in the stream.
We need to define a Predicate instance with the comparison logic and provide this Predicate as an input to the matching methods. Then, Java 8 processes the matching function internally and provides you with the result whether a match for the condition was found or not.
Stream.allMatch: We pass the Predicate as an argument to the allMatch()
method. That Predicate is applied to each element of the stream, and if each and every element satisfies the given Predicate, then it returns true — otherwise false.
Stream.anyMatch: For the anyMatch()
method, we pass the Predicate as an argument. The element of the stream is iterated for this Predicate. If any element matches, then it returns true — otherwise false.
Stream.noneMatch: The noneMatch()
method is a method that takes an argument as a Predicate, and if none of the elements of the stream matches the given Predicate, then it returns true — otherwise false.
Now let us check some examples of these methods. We will have a simple model class, Employee
, for all our examples:
package com.tuturself.stream;
public class Employee {
private int id;
private String name;
private int age;
private int salary;
public Employee(int id, String name, int age, int salary) {
super();
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public int getSalary() {
return salary;
}
}
Now we will define some predicates for checking some conditions that will be used in these methods.
package com.tuturself.stream;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class EmployeePredicates {
public static Predicate < Employee > isAdult() {
return p - > p.getAge() > StreamTest.ADULT;
}
public static Predicate < Employee > isSalaryMoreThan(Integer salary) {
return p - > p.getSalary() > salary;
}
public static List < Employee > filterAndGetEmployees(List < Employee > employees, Predicate < Employee > predicate) {
return employees.stream().filter(predicate)
.collect(Collectors. < Employee > toList());
}
}
Now consider the following test cases for all these methods.
package com.tuturself.stream;
import java.util.ArrayList;
import java.util.List;
public class StreamTest {
public static int ADULT = 18;
public static List < Employee > getEmployeeList() {
List < Employee > employeeList = new ArrayList < > ();
employeeList.add(new Employee(1, "Ninja Panda", 32, 200));
employeeList.add(new Employee(2, "Maste Shifu", 36, 250));
employeeList.add(new Employee(3, "Aidan Lloyd", 22, 300));
employeeList.add(new Employee(4, "Aidan Lloyd", 34, 700));
employeeList.add(new Employee(5, "PandaLuca Gallagher", 30, 1200));
return employeeList;
}
public static void main(String[] args) {
List < Employee > employeeList = getEmployeeList();
// is all employees are Adult.
System.out.println("Are all employees are adult: " +
employeeList.stream().allMatch(EmployeePredicates.isAdult()));
// is there is an employee whose salary is more than 1000
System.out.println("Has employee with more than 1000 salary: " +
employeeList.stream()
.anyMatch(EmployeePredicates.isSalaryMoreThan(1000)));
// is there is an employee whose salary is more than 1000
System.out.println("Has employee with more than 1500 salary: " +
employeeList.stream()
.anyMatch(EmployeePredicates.isSalaryMoreThan(1500)));
// do we have an employee named Andy
System.out.println("We do not have an employee named Andy: " +
employeeList.stream()
.noneMatch(e - > e.getName().contains("Andy")));
}
}
So, the predicates can be defined externally as defined in the EmployeePredicates
class or can be provided in these methods itself, as we did for the noneMatch()
method. The Predicate is provided as e-> e.getName().contains("Andy")
. The output of the program is:
Are all employees are adult: true
Has employee with more than 1000 salary: true
Has employee with more than 1500 salary: false
We do not have an employee named Andy: true
We can collect all the elements matching the given Predicate to some Collection. Check the following method from the EmployeePredicates
class.
public static List < Employee > filterAndGetEmployees(List < Employee > employees,
Predicate < Employee > predicate) {
return employees.stream().filter(predicate).collect(Collectors. < Employee > toList());
}
Let us collect and print the names of all the Employees earning more than 300.
List<Employee> salaryMoreThan300 = EmployeePredicates.filterAndGetEmployees(employeeList,
EmployeePredicates.isSalaryMoreThan(300));
salaryMoreThan300.forEach(e -> System.out.println(e.getName()));
The output of the program is:
Aidan Lloyd
PandaLuca Gallagher
Compare Two Lists by These Matching Methods?
Now let us come back to the earlier program, where we were comparing two Lists
' content with Java 7. Let us rewrite the program in Java 8 using these matching methods.
package com.tuturself;
import java.util.Arrays;
import java.util.List;
public class ListCompare {
public static void main(String[] args) {
List < Integer > aList = Arrays.asList(new Integer[] {
1,
3,
5,
6,
8
});
List < Integer > bList = Arrays.asList(new Integer[] {
10,
89,
8,
9
});
// If any number from List is present in List 2
System.out.println(
"If any number from aList is present in List 2 :" +
aList.stream().anyMatch(num - > bList.contains(num)));
// If any number from List is present in List 2
System.out.println(
"If any number from aList is not present in List 2 :" +
aList.stream().noneMatch(num - > bList.contains(num)));
// If any number from List is present in List 2
System.out.println(
"If all numbers from aList are present in List 2 :" +
aList.stream().allMatch(num - > bList.contains(num)));
}
}
Now, the output of the program is:
If any number from aList is present in List 2 :true
If any number from aList is not present in List 2 :false
If all numbers from aList are present in List 2 :true
If you enjoyed this article and want to learn more about Java Streams, check out this collection of tutorials and articles on all things Java Streams.
Published at DZone with permission of Arpan Das. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments