在Java开发中,判断两个集合是否存在交集是高频需求,比如校验两个用户组的权限是否有重叠、判断两个商品标签是否有共同项等场景都需要用到这个能力。不同的实现方式在代码简洁度和性能上有所差异,开发者可以根据实际场景选择。

方法一:使用Collection的retainAll方法
Java的Collection接口提供了retainAll方法,该方法的作用是保留集合中存在于指定集合里的元素,也就是求两个集合的交集。我们可以通过判断调用该方法后集合是否发生变化,来间接判断两个集合是否有交集。
实现逻辑是:先拷贝一个原集合的副本,然后调用副本的retainAll方法传入另一个集合,如果副本的元素数量发生了变化,说明两个集合存在交集。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class CollectionIntersectionDemo {
public static void main(String[] args) {
// 定义第一个集合
List<String> list1 = new ArrayList<>();
list1.add("apple");
list1.add("banana");
list1.add("orange");
// 定义第二个集合
List<String> list2 = new ArrayList<>();
list2.add("banana");
list2.add("grape");
list2.add("pear");
// 判断两个集合是否有交集
boolean hasIntersection = hasIntersectionByRetainAll(list1, list2);
System.out.println("两个集合是否有交集:" + hasIntersection);
}
/**
* 使用retainAll方法判断两个集合是否有交集
* @param coll1 第一个集合
* @param coll2 第二个集合
* @return 有交集返回true,否则返回false
*/
private static boolean hasIntersectionByRetainAll(Collection<?> coll1, Collection<?> coll2) {
// 拷贝第一个集合,避免修改原集合
Collection<?> tempColl = new ArrayList<>(coll1);
// 求交集,返回值是集合是否发生了改变
boolean changed = tempColl.retainAll(coll2);
// 如果集合发生了改变,说明存在交集
return changed;
}
}
这种方式的优点是代码简洁,不需要自己写遍历逻辑,但是retainAll方法会修改拷贝的集合,不过因为我们提前做了拷贝,所以不会影响原集合。需要注意的是,如果集合元素较多,拷贝集合会有一定的内存开销。
方法二:使用循环遍历判断
如果不想使用retainAll方法,也可以通过循环遍历其中一个集合的元素,判断是否存在于另一个集合中,只要找到一个共同元素就可以返回结果,不需要遍历完所有元素。
为了提升查询效率,建议把元素较多的集合转成HashSet,这样查询元素的时间复杂度是O(1),整体时间复杂度是O(n),n是较小集合的元素数量。
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class LoopIntersectionDemo {
public static void main(String[] args) {
List<Integer> list1 = new ArrayList<>();
list1.add(1);
list1.add(2);
list1.add(3);
List<Integer> list2 = new ArrayList<>();
list2.add(3);
list2.add(4);
list2.add(5);
boolean hasIntersection = hasIntersectionByLoop(list1, list2);
System.out.println("两个集合是否有交集:" + hasIntersection);
}
/**
* 使用循环遍历判断两个集合是否有交集
* @param coll1 第一个集合
* @param coll2 第二个集合
* @return 有交集返回true,否则返回false
*/
private static boolean hasIntersectionByLoop(Collection<?> coll1, Collection<?> coll2) {
// 处理空集合的情况
if (coll1 == null || coll2 == null || coll1.isEmpty() || coll2.isEmpty()) {
return false;
}
// 把元素较多的集合转成HashSet,提升查询效率
Collection<?> smallerColl = coll1.size() <= coll2.size() ? coll1 : coll2;
Collection<?> largerColl = coll1.size() <= coll2.size() ? coll2 : coll1;
Set<Object> tempSet = new HashSet<>(largerColl);
// 遍历较小集合的元素,判断是否存在于较大集合中
for (Object item : smallerColl) {
if (tempSet.contains(item)) {
return true;
}
}
return false;
}
}
这种方式的灵活性更高,而且不需要修改原集合,也不需要拷贝整个集合做交集运算,在元素数量较多的时候性能表现更好,尤其是当两个集合大小差异较大的时候,优势更明显。
方法三:使用Apache Commons Collections工具类
如果项目中已经引入了Apache Commons Collections依赖,可以直接使用工具类提供的CollectionUtils.containsAny方法,该方法可以直接判断两个集合是否有交集,内部实现也是基于循环遍历的逻辑,但是封装得更加完善,还处理了null值的情况。
首先需要引入对应的依赖,如果是Maven项目,可以在pom.xml中添加如下配置:
<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 CommonsIntersectionDemo {
public static void main(String[] args) {
List<String> list1 = Arrays.asList("a", "b", "c");
List<String> list2 = Arrays.asList("c", "d", "e");
// 直接调用工具类方法判断是否有交集
boolean hasIntersection = CollectionUtils.containsAny(list1, list2);
System.out.println("两个集合是否有交集:" + hasIntersection);
}
}
这种方式的代码最简洁,适合已经引入相关依赖的项目,但是如果没有相关依赖,为了这个功能单独引入会增加项目的依赖体积,需要权衡是否使用。
不同方法的对比
我们可以通过下面的表格对比三种方法的优缺点和适用场景:
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| retainAll方法 | 代码简洁,无需自己实现遍历逻辑 | 需要拷贝集合,有内存开销,会修改拷贝的集合 | 集合元素较少,追求代码简洁的场景 |
| 循环遍历 | 性能较好,无需额外依赖,不修改原集合 | 需要自己实现逻辑,代码量稍多 | 集合元素较多,对性能要求高的场景 |
| Apache Commons工具类 | 代码最简洁,处理了边界情况 | 需要额外引入依赖 | 项目已经引入相关依赖的场景 |
注意事项
- 判断交集前需要先处理集合为null或者空集合的情况,避免出现空指针异常。
- 如果集合中的元素是自定义对象,需要确保对象正确重写了
equals和hashCode方法,否则判断元素是否存在的时候会出现不符合预期的结果。 - 如果集合是有序的,比如
TreeSet,可以利用有序的特性做更高效的判断,比如双指针遍历,但是实现逻辑会更复杂,一般场景不需要这么做。
Java集合交集判断CollectionretainAll修改时间:2026-07-20 14:30:39