在 Java 中,计算两个集合的差集是一个常见的操作。然而,在实际开发中,我们常常需要的不仅是简单的差集,还可能是两个集合的对称差。对称差指的是集合 A 中独有的元素和集合 B 中独有的元素的组合。本文将介绍几种实现对称差的方式,并提供代码示例。
什么是对称差?
给定两个集合:
- 集合1:
{1, 2, 3, 4}
- 集合2:
{2, 3, 4}
两者的对称差是:{1}
。
实现方法
方法 1:使用 removeAll
两次实现对称差
removeAll
是 Java 集合的基础方法,用于移除一个集合中与另一个集合相同的元素。通过两次 removeAll
,分别计算集合 1 和集合 2 的差集,再将结果合并。
import java.util.HashSet;
import java.util.Set;public class SymmetricDifferenceExample {public static void main(String[] args) {Set<Integer> set1 = new HashSet<>();set1.add(1);set1.add(2);set1.add(3);set1.add(4);Set<Integer> set2 = new HashSet<>();set2.add(2);set2.add(3);set2.add(4);// 计算对称差Set<Integer> difference = new HashSet<>(set1);difference.removeAll(set2); // set1 中独有的元素Set<Integer> temp = new HashSet<>(set2);temp.removeAll(set1); // set2 中独有的元素difference.addAll(temp); // 合并结果System.out.println("对称差: " + difference); // 输出: 对称差: [1]}
}
方法 2:使用 Java 8 的流式操作
流式操作(Stream)提供了更优雅的方式来处理集合操作。通过 filter
筛选条件,可以高效实现对称差。
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;public class SymmetricDifferenceExample {public static void main(String[] args) {List<Integer> list1 = Arrays.asList(1, 2, 3, 4);List<Integer> list2 = Arrays.asList(2, 3, 4);// 使用流计算对称差Set<Integer> difference = Stream.concat(list1.stream().filter(item -> !list2.contains(item)),list2.stream().filter(item -> !list1.contains(item))).collect(Collectors.toSet());System.out.println("对称差: " + difference); // 输出: 对称差: [1]}
}
方法 3:使用 Guava 的 Sets.symmetricDifference
如果项目中已引入 Google Guava 库,可以直接调用 Sets.symmetricDifference
方法,它是专门为计算对称差设计的。
Maven 依赖:
<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>32.0.1-jre</version>
</dependency>
代码示例:
import com.google.common.collect.Sets;
import java.util.Set;
import java.util.HashSet;public class SymmetricDifferenceExample {public static void main(String[] args) {Set<Integer> set1 = new HashSet<>();set1.add(1);set1.add(2);set1.add(3);set1.add(4);Set<Integer> set2 = new HashSet<>();set2.add(2);set2.add(3);set2.add(4);// 使用 Guava 计算对称差Set<Integer> difference = Sets.symmetricDifference(set1, set2);System.out.println("对称差: " + difference); // 输出: 对称差: [1]}
}
方法 4:手动遍历实现对称差
如果不使用高级库或 Java 8 特性,可以通过手动遍历集合来实现对称差。这种方法在某些场景下更容易理解和调试。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;public class SymmetricDifferenceExample {public static void main(String[] args) {List<Integer> list1 = new ArrayList<>();list1.add(1);list1.add(2);list1.add(3);list1.add(4);List<Integer> list2 = new ArrayList<>();list2.add(2);list2.add(3);list2.add(4);// 存储结果Set<Integer> difference = new HashSet<>();// 遍历 list1,添加独有元素for (Integer item : list1) {if (!list2.contains(item)) {difference.add(item);}}// 遍历 list2,添加独有元素for (Integer item : list2) {if (!list1.contains(item)) {difference.add(item);}}System.out.println("对称差: " + difference); // 输出: 对称差: [1]}
}
方法 5:使用 Apache Commons Collections 的 CollectionUtils.disjunction
Apache Commons Collections 提供了 CollectionUtils.disjunction
方法,可以直接计算两个集合的对称差。
Maven 依赖:
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.4</version>
</dependency>
代码示例:
import org.apache.commons.collections4.CollectionUtils;
import java.util.Arrays;
import java.util.List;public class SymmetricDifferenceExample {public static void main(String[] args) {List<Integer> list1 = Arrays.asList(1, 2, 3, 4);List<Integer> list2 = Arrays.asList(2, 3, 4);// 使用 CollectionUtils 计算对称差List<Integer> difference = (List<Integer>) CollectionUtils.disjunction(list1, list2);System.out.println("对称差: " + difference); // 输出: 对称差: [1]}
}
性能分析与总结
方法 | 优点 | 缺点 |
---|---|---|
removeAll 两次 | 简单直观,易于理解 | 操作两个集合需要额外空间 |
Java 8 Stream | 灵活,代码优雅,适合复杂需求 | 需要 Java 8 支持 |
Guava Sets.symmetricDifference | 代码简洁,性能高 | 需要引入 Guava 库 |
手动遍历 | 控制力强,适合无第三方库的项目 | 代码繁琐,不适合大数据集 |
Apache CollectionUtils | 直接调用现成方法 | 需要引入 Commons 库 |
推荐使用 Guava
或 Java 8 的流式操作。如果项目中已有这些依赖,这两种方式更高效、优雅。对于不支持 Java 8 的老项目,可以选择手动遍历或者 removeAll
。