Java 中求两个 List集合的交集元素
在 Java 中,求两个 List
的交集元素可以通过多种方式实现。常见的做法包括使用 retainAll
方法、Stream
API 或手动遍历。以下是这些方法的原理和实现:
1. 使用 retainAll
方法
retainAll
是 Collection
接口中的一个方法,用于保留集合中与指定集合相同的元素,移除其他元素。
原理:
retainAll
方法会遍历当前集合,并检查每个元素是否存在于指定集合中。- 如果元素不存在于指定集合中,则从当前集合中移除该元素。
- 最终,当前集合只保留与指定集合相同的元素。
retainAll
是 Java 中 List
接口提供的一个方法,用于保留列表中与指定集合中相同的元素,移除其他所有元素。换句话说,retainAll
方法会修改当前列表,使其仅包含与指定集合中相同的元素。
方法定义
boolean retainAll(Collection<?> c);
参数:
c
:包含需要保留元素的集合。
返回值:
- 如果列表因调用此方法而发生变化,则返回
true
。 - 如果列表未发生变化(即列表已经只包含指定集合中的元素),则返回
false
。
方法行为
- 保留交集:
retainAll
方法会保留当前列表与指定集合的交集。 - 移除其他元素:当前列表中不在指定集合中的元素会被移除。
- 修改原列表:
retainAll
方法会直接修改当前列表,而不是返回一个新的列表。
示例代码
以下是一个简单的示例,展示 retainAll
方法的使用:
import java.util.ArrayList;
import java.util.List;
public class RetainAllExample {
public static void main(String[] args) {
// 创建两个列表
List<String> list1 = new ArrayList<>();
list1.add("Apple");
list1.add("Banana");
list1.add("Cherry");
list1.add("Date");
List<String> list2 = new ArrayList<>();
list2.add("Banana");
list2.add("Date");
list2.add("Fig");
// 调用 retainAll 方法
boolean isChanged = list1.retainAll(list2);
// 输出结果
System.out.println("List1 是否发生变化: " + isChanged); // true
System.out.println("List1 的内容: " + list1); // [Banana, Date]
System.out.println("List2 的内容: " + list2); // [Banana, Date, Fig]
}
}
输出:
List1 是否发生变化: true
List1 的内容: [Banana, Date]
List2 的内容: [Banana, Date, Fig]
关键点
-
修改原列表:
retainAll
方法会直接修改调用它的列表,而不是返回一个新的列表。- 如果需要保留原列表,可以在调用
retainAll
之前创建一个副本。
-
返回值:
- 如果列表因调用
retainAll
而发生变化,则返回true
。 - 如果列表未发生变化(即列表已经只包含指定集合中的元素),则返回
false
。
- 如果列表因调用
-
集合比较:
retainAll
方法依赖于equals
方法来比较元素是否相同。- 如果集合中包含自定义对象,请确保正确重写了
equals
和hashCode
方法。
-
空集合:
- 如果传入的集合为空(
null
或空集合),retainAll
会抛出NullPointerException
或清空当前列表。
- 如果传入的集合为空(
注意事项
-
性能问题:
retainAll
方法的时间复杂度取决于列表的实现。对于ArrayList
,时间复杂度为 O(n*m),其中 n 是列表的大小,m 是集合的大小。- 如果列表和集合都很大,性能可能会受到影响。
-
集合类型:
retainAll
方法可以接受任何实现了Collection
接口的对象作为参数,例如List
、Set
等。
-
元素重复:
- 如果列表中有重复元素,而指定集合中没有重复元素,
retainAll
会保留列表中的重复元素。 - 例如:
List<String> list1 = new ArrayList<>(List.of("A", "A", "B", "C")); List<String> list2 = new ArrayList<>(List.of("A", "B")); list1.retainAll(list2); System.out.println(list1); // 输出 [A, A, B]
- 如果列表中有重复元素,而指定集合中没有重复元素,
注:
retainAll
方法用于保留列表中与指定集合中相同的元素,移除其他元素。- 它会直接修改原列表,并返回一个布尔值表示列表是否发生变化。
- 使用时需要注意性能问题和集合类型的兼容性。
- 如果需要保留原列表,可以在调用
retainAll
之前创建一个副本。
2. 使用 Stream
API
Java 8 引入了 Stream
API,可以方便地对集合进行操作。
原理:
- 使用
stream()
方法将List
转换为流。 - 使用
filter
方法过滤出存在于另一个集合中的元素。 - 使用
collect
方法将结果收集到一个新的List
中。
示例代码:
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
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(2);
list2.add(3);
list2.add(4);
List<Integer> intersection = list1.stream()
.filter(list2::contains)
.collect(Collectors.toList());
System.out.println(intersection); // 输出: [2, 3]
}
}
3. 手动遍历
手动遍历两个 List
,并找出共同的元素。
原理:
- 遍历第一个
List
中的每个元素。 - 检查该元素是否存在于第二个
List
中。 - 如果存在,则将其添加到结果集合中。
示例代码:
import java.util.ArrayList;
import java.util.List;
public class Main {
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(2);
list2.add(3);
list2.add(4);
List<Integer> intersection = new ArrayList<>();
for (Integer item : list1) {
if (list2.contains(item)) {
intersection.add(item);
}
}
System.out.println(intersection); // 输出: [2, 3]
}
}
总结
retainAll
方法是最直接的方式,但会修改原始集合。Stream
API 提供了更灵活和函数式的编程方式,且不会修改原始集合。- 手动遍历适用于需要自定义逻辑的场景,但代码量较多。
根据具体需求选择合适的方法即可。