Java 11+优雅对比对象列表差异:基于value属性的实现
Java 11及以上版本中优雅对比对象列表差异的方案
需求说明
我们需要基于ColValueObject的value属性,找出两个对象列表的差异——也就是只在其中一个列表中出现的元素。示例场景:
- 列表1:
( { "left","one" }, { "left","two" } ) - 列表2:
( { "right","two" }, { "right","three" } )
预期结果:( { "left","one" }, { "right","three" } )
传统嵌套循环实现冗余且效率偏低(时间复杂度O(n*m)),以下是几种更优雅的实现方案:
方案1:Stream+Set快速查找(高效简洁)
先提取两个列表的value到Set中(利用Set的O(1)查找特性),再通过Stream过滤出仅在单个列表存在的元素:
import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.stream.Collectors; public class CompareListOfObjects { public static void main(String[] args) { List<ColValueObject> list1 = List.of( new ColValueObject("left", "Value one"), new ColValueObject("left", "Value two"), new ColValueObject("left", "Value three")); List<ColValueObject> list2 = List.of( new ColValueObject("right", "Value two"), new ColValueObject("right", "Value three"), new ColValueObject("right", "Value four")); List<ColValueObject> result = findDifferencesBetweenLists(list1, list2); result.forEach(System.out::println); } private static List<ColValueObject> findDifferencesBetweenLists(List<ColValueObject> list1, List<ColValueObject> list2) { // 提取两个列表的value集合,用于快速校验 Set<String> list1Values = list1.stream() .map(ColValueObject::getValue) .collect(Collectors.toSet()); Set<String> list2Values = list2.stream() .map(ColValueObject::getValue) .collect(Collectors.toSet()); // 筛选出仅在单个列表中存在的元素 List<ColValueObject> diff = new ArrayList<>(); diff.addAll(list1.stream() .filter(obj -> !list2Values.contains(obj.getValue())) .collect(Collectors.toList())); diff.addAll(list2.stream() .filter(obj -> !list1Values.contains(obj.getValue())) .collect(Collectors.toList())); return diff; } } class ColValueObject { private String base; private String value; public ColValueObject(String base, String value) { this.base = base; this.value = value; } public String getBase() { return base; } public void setBase(String base) { this.base = base; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } @Override public String toString() { return "ColValueObject{" + "base='" + base + '\'' + ", value='" + value + '\'' + '}'; } }
该方案时间复杂度优化为O(n+m),兼顾效率与可读性。
方案2:Collectors分组筛选(声明式风格)
通过合并列表并标记来源,按value分组后筛选出仅在单一来源出现的元素,更贴合函数式编程风格:
import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; public class CompareListOfObjects { // main方法同方案1,此处省略 private static List<ColValueObject> findDifferencesBetweenLists(List<ColValueObject> list1, List<ColValueObject> list2) { // 合并列表并标记元素来源 List<SourceMarkedObject> merged = new ArrayList<>(); merged.addAll(list1.stream().map(obj -> new SourceMarkedObject(obj, "list1")).collect(Collectors.toList())); merged.addAll(list2.stream().map(obj -> new SourceMarkedObject(obj, "list2")).collect(Collectors.toList())); // 按value分组,收集每个value对应的来源集合 Map<String, Set<String>> valueSourceMap = merged.stream() .collect(Collectors.groupingBy( item -> item.obj.getValue(), Collectors.mapping(item -> item.source, Collectors.toSet()) )); // 筛选出仅在单个列表出现的元素 return merged.stream() .filter(item -> valueSourceMap.get(item.obj.getValue()).size() == 1) .map(item -> item.obj) .collect(Collectors.toList()); } // 辅助类:标记元素所属列表 static class SourceMarkedObject { ColValueObject obj; String source; public SourceMarkedObject(ColValueObject obj, String source) { this.obj = obj; this.source = source; } } } // ColValueObject类同方案1,此处省略
这种写法逻辑清晰,便于后续扩展复杂的对比规则。
方案3:借助Apache Commons Collections(简洁依赖版)
如果项目已引入Apache Commons Collections库,可直接利用工具类简化代码:
import org.apache.commons.collections4.CollectionUtils; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class CompareListOfObjects { // main方法同方案1,此处省略 private static List<ColValueObject> findDifferencesBetweenLists(List<ColValueObject> list1, List<ColValueObject> list2) { // 提取两个列表的value列表 List<String> list1Values = list1.stream().map(ColValueObject::getValue).collect(Collectors.toList()); List<String> list2Values = list2.stream().map(ColValueObject::getValue).collect(Collectors.toList()); // 利用工具类获取value的对称差集 List<String> diffValues = new ArrayList<>(CollectionUtils.disjunction(list1Values, list2Values)); // 从原列表中筛选对应元素 List<ColValueObject> result = new ArrayList<>(); result.addAll(list1.stream().filter(obj -> diffValues.contains(obj.getValue())).collect(Collectors.toList())); result.addAll(list2.stream().filter(obj -> diffValues.contains(obj.getValue())).collect(Collectors.toList())); return result; } } // ColValueObject类同方案1,此处省略
该方案代码最简洁,但需要引入第三方依赖:
<!-- Maven依赖示例 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.4</version> </dependency>
内容的提问来源于stack exchange,提问作者tm1701
相关产品推荐
相关产品推荐

