Comparing Collections Using Java Stream API
This article explains how to log pre‑update data, compare old and new records, and use Java Stream operations such as filter, collect, anyMatch, noneMatch, and contains to identify differences between collections, including custom objects, with code examples and best‑practice recommendations.
In a previous development scenario, the need arose to record the data before an update operation as a log that administrators can view.
The author considered two approaches: comparing the incoming data with the current database record, or retrieving the record before and after the update and comparing them. The second approach was chosen because backend verification ensures the same record is being updated.
Collection comparison
To compare two collections of custom objects, the article recommends using Stream.filter() combined with collect(Collectors.toList()) to obtain a new list of differing elements. Example code:
@Test
public void testFilter() {
// first list
List
list1 = new ArrayList<>();
list1.add(new ListData("测测名字11", 11, "email@11"));
list1.add(new ListData("测测名字22", 22, "email@22"));
list1.add(new ListData("测测名字33", 33, "email@33"));
log.info("第一个数组为:{}", list1);
// second list
List
list2 = new ArrayList<>();
list2.add(new ListData("测测名字111", 111, "email@11"));
list2.add(new ListData("测测名字22", 22, "email@22"));
list2.add(new ListData("测测名字33", 33, "email@33"));
log.info("第二个数组为:{}", list2);
List
resultList = list1.stream()
.filter(p1 -> list2.stream()
.filter(p2 -> p2.getName().equals(p1.getName()) && p2.getAge().equals(p1.getAge()))
.findFirst().orElse(null) == null)
.collect(Collectors.toList());
log.info("经过 Stream 流处理后输出的结果数组为: {}", resultList);
}Alternative implementations using noneMatch() or contains() achieve the same result.
List
resultList = list1.stream()
.filter(p1 -> list2.stream()
.noneMatch(p2 -> p2.getName().equals(p1.getName()) && p2.getAge().equals(p1.getAge())))
.collect(Collectors.toList());
log.info("经过 Stream 流处理后输出的结果数组为: {}", resultList);For a simple boolean check, anyMatch() or allMatch() can be used:
boolean flag = list1.stream()
.anyMatch(p1 -> list2.stream()
.allMatch(p2 -> p2.getName().equals(p1.getName()) && p2.getAge().equals(p1.getAge())));
log.info("经过 Stream 流对比是否相等: {}", flag);The article also shows how to compare simple collections of integers or strings by sorting and using equals, and how to compare custom objects by implementing equals() or providing a Comparator.
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ListData {
private String name;
private Integer age;
private String email;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ListData listData = (ListData) o;
return Objects.equals(name, listData.name) &&
Objects.equals(age, listData.age) &&
Objects.equals(email, listData.email);
}
}Finally, the article reviews the basics of the Java Stream API, including how to create streams from collections, arrays, or the Stream.of() method, the categories of intermediate operations (filter, map, sorted), and terminal operations such as anyMatch, allMatch, noneMatch, findFirst, count, collect, and forEach.
It concludes that mastering Stream operations can greatly improve backend development efficiency, and suggests using IDE tools like “Trace Current Stream Chain” for debugging.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.