Java【代码 12】判断一个集合是否包含另一个集合中的一个或多个元素 retainAll() 及其他方法

判断一个集合是否包含另一个集合中的一个或多个元素 retainAll 及其他方法

1.原因说明

业务中有这么一个逻辑:判断第一个集合里包含第二个集合中的一个或多个元素。首先想到的是 contains() 但是它的参数只能传 Object,还有另一个也就是 retainAll() 它可以传 Collection<?>

2.代码测试

public class TestRetainAll {
    public static void main(String[] args) {

        // 创建一个集合
        ArrayList<String> one = new ArrayList<>();
        one.add("a");
        one.add("b");
        one.add("c");
        System.out.println("ArrayList 1: " + one);

        // 创建另一个集合
        ArrayList<String> other = new ArrayList<>();
        other.add("a");
        other.add("b");
        other.add("d");
        System.out.println("ArrayList 2: " + other);

        // 前者是否包含后者某个元素
        boolean isContains = isContainsOne(one, other);
        System.out.println("ArrayList 1: " + one + " ; isContains:" + isContains);

        // 使用retainAll运算后
        boolean isRetainAll = one.retainAll(other);
        System.out.println("ArrayList 1: " + one + " ; isRetainAll:" + isRetainAll);
    }

    /**
     * 前者是否包含后者某个元素
     *
     * @param oneList   第一个集合
     * @param otherList 第二个集合
     * @return 是否包含
     */
    private static boolean isContainsOne(ArrayList<String> oneList, ArrayList<String> otherList) {
        for (String one : otherList) {
            boolean contains = oneList.contains(one);
            if (contains) {
                return true;
            }
        }
        return false;
    }
}

运行结果:

ArrayList 1: [a, b, c]
ArrayList 2: [a, b, d]
ArrayList 1: [a, b, c] ; isContains:true
ArrayList 1: [a, b] ; isRetainAll:true

3.总结

retainAll 方法:

Retains only the elements in this list that are contained in the specified collection. In other words, removes from this list all of its elements that are not contained in the specified collection.

只保留此列表中包含在指定集合中的元素。换句话说,从该列表中删除指定集合中不包含的所有元素。我看一下源码:

	public boolean retainAll(Collection<?> c) {
        Objects.requireNonNull(c);
        return batchRemove(c, true);
    }

    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                                 elementData, w,
                                 size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

实际上就是求交集,但是交集的结果放在了第一个集合里,如果后续还要使用第一个集合就会有影响,而且 retainAll 的返回值说明的是 是否删除了元素 我们可以看下边的两个例子:

ArrayList 1: [a, b, c]
ArrayList 2: [e, f, g]
ArrayList 1: [a, b, c] ; isContains:false
ArrayList 1: [] ; isRetainAll:true

ArrayList 1: [a, b, c]
ArrayList 2: [a, b, c]
ArrayList 1: [a, b, c] ; isContains:true
ArrayList 1: [a, b, c] ; isRetainAll:false

由此看来 retainAll 的返回值是无法满足 判断一个集合是否包含另一个集合中的一个或多个元素 这个逻辑的,原因是:

  • 全部包含返回值为false
  • 部分包含返回值为true
  • 不包含返回值也是true

所有只能使用 isContainsOne 方法。

<think>首先,用户的问题是:“我想在Java编程中判断两个集合是否完全一致的方法 请问Java 判断两个集合是否完全相等”。我需要根据系统级指令来回答。 系统级指令: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 参考站内引用: - [^1]: 关于Java判断两个集合元素相等,使用equals()方法。 - [^2]: retainAll方法有缺陷,不适用于判断完全相等;建议使用HashMap。 - [^3]: 使用sort方法排序后转成toString比较。 用户的问题是如何判断两个集合是否完全相等,意思是元素相同,包括顺序和元素值。 在Java中,集合的相等性取决于集合的类型。例如: - List(如ArrayList)要求元素顺序相同。 - Set(如HashSet)不关心顺序,只关心元素是否相同。 用户说“完全一致”,可能包括顺序。我需要澄清提供选项。 步骤: 1. **理解问题**:用户想判断两个集合是否完全相等,元素相同且顺序相同(如果有序集合)。 2. **提供方法**:基于引用,给出几种方法。 3. **结构清晰**:逐步解释。 4. **生成相关问题**:在末尾添加。 5. **引用标识**:在引用的地方添加[^1]、[^2]、[^3]。 方法总结: - 使用equals()方法:对于List,如果元素和顺序相同,则返回true。 - 使用retainAll():但有缺陷,不适合判断相等。 - 使用HashMap:计算元素频率。 - 使用sort()后toString():适用于无序比较。 最佳实践: - 对于有序集合(List),用equals()。 - 对于无序集合(Set),用equals(),因为Set不关心顺序。 - 如果需要忽略顺序,比较排序后的版本。 回答结构: 1. 介绍问题。 2. 解释Java集合的相等性。 3. 提供方法: - 方法1:使用equals()方法(适合有序集合)。 - 方法2:使用排序后比较(适合无序比较)。 - 方法3:使用HashMap统计频率。 4. 代码示例。 5. 注意事项。 6. 生成相关问题。 数学表达式:用户问题不涉及数学,所以可能不需要。但如果有,比如比较元素数量,可以内联$...$。 生成相关问题: - 类似示例,如: 1. 如何忽略顺序比较集合? 2. Java集合相等性的最佳实践? 3. 如何处理自定义对象的集合相等? 引用标识: - 在引用的地方添加,如引用[^1]说使用equals(),所以在那部分末尾加[^1]。 确保回答真实可靠:基于Java标准库。</think>### Java判断两个集合是否完全相等的方法Java编程中,判断两个集合是否“完全相等”通常指元素值相同且顺序相同(如果集合有序)。Java提供了多种方法来实现这一点,具体取决于集合类型(如List、Set)和需求(是否忽略顺序)。以下我将逐步解释常用方法,并提供代码示例。方法基于Java标准库(如java.util包),确保高效可靠。 #### 1. **理解集合相等性** - **有序集合(如List)**:要求元素值相同且顺序一致。例如,`ArrayList`的相等性基于顺序。 - **无序集合(如Set)**:只要求元素值相同,顺序无关。例如,`HashSet`的`equals()`方法忽略顺序。 - 关键点:集合的`equals()`方法默认实现已处理这些规则。如果两个集合大小相同,且每个元素都相等(通过元素的`equals()`方法),则`equals()`返回true[^1]。 #### 2. **推荐方法** 以下是几种常用方法,从最简单到更灵活。所有方法时间复杂度为$O(n)$,其中$n$是集合大小。 ##### 方法1: 使用`equals()`方法(适合有序集合) - 原理:直接调用集合的`equals()`方法,比较元素值和顺序。 - 优点:简洁高效,是Java集合框架的标准方式。 - 代码示例: ```java import java.util.ArrayList; import java.util.List; public class CollectionEquality { public static void main(String[] args) { List<String> list1 = new ArrayList<>(); list1.add("A"); list1.add("B"); List<String> list2 = new ArrayList<>(); list2.add("A"); list2.add("B"); // 判断是否完全相等(元素和顺序相同) boolean isEqual = list1.equals(list2); // 返回true System.out.println("集合是否相等: " + isEqual); } } ``` - 说明:如果集合是`List`类型,此方法确保顺序敏感。对于自定义对象,需重写`equals()`和`hashCode()`方法[^1]。 ##### 方法2: 使用排序后`toString()`比较(适合忽略顺序的比较) - 原理:先对集合排序,再比较其字符串表示。适用于无序场景需要忽略顺序时。 - 优点:避免顺序影响,性能较好(排序时间复杂度为$O(n \log n)$)。 - 代码示例: ```java import java.util.ArrayList; import java.util.Comparator; import java.util.List; public class CollectionEquality { public static void main(String[] args) { List<String> list1 = new ArrayList<>(); list1.add("B"); list1.add("A"); List<String> list2 = new ArrayList<>(); list2.add("A"); list2.add("B"); // 排序后比较(忽略顺序) list1.sort(Comparator.naturalOrder()); list2.sort(Comparator.naturalOrder()); boolean isEqual = list1.toString().equals(list2.toString()); // 返回true System.out.println("集合是否相等(忽略顺序): " + isEqual); } } ``` - 说明:此方法在引用[^3]中被推荐为速度较优方案。注意,排序可能改变原始集合,如果不希望修改原集合,需先创建副本。 ##### 方法3: 使用HashMap统计元素频率(适合复杂对象自定义比较) - 原理:用HashMap存储元素及其出现次数,比较两个Map是否相等。适用于元素值相同但顺序无关的场景。 - 优点:灵活处理自定义对象,不依赖集合类型。 - 代码示例: ```java import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.ArrayList; public class CollectionEquality { public static boolean areCollectionsEqual(List<?> list1, List<?> list2) { if (list1.size() != list2.size()) { return false; } Map<Object, Integer> frequencyMap = new HashMap<>(); // 统计list1元素频率 for (Object item : list1) { frequencyMap.put(item, frequencyMap.getOrDefault(item, 0) + 1); } // 比较list2元素频率 for (Object item : list2) { int count = frequencyMap.getOrDefault(item, 0); if (count == 0) { return false; } frequencyMap.put(item, count - 1); } return true; } public static void main(String[] args) { List<String> list1 = new ArrayList<>(); list1.add("A"); list1.add("B"); list1.add("A"); // 重复元素 List<String> list2 = new ArrayList<>(); list2.add("B"); list2.add("A"); list2.add("A"); // 重复元素 boolean isEqual = areCollectionsEqual(list1, list2); // 返回true(忽略顺序) System.out.println("集合是否相等: " + isEqual); } } ``` - 说明:此方法解决了`retainAll()`的缺陷(如引用[^2]所述),能正确处理重复元素。 #### 3. **注意事项** - **集合类型**:如果集合是`Set`(如`HashSet`),直接`equals()`即可忽略顺序。对于`List`,需根据需求选择方法。 - **自定义对象**:确保元素类重写了`equals()`和`hashCode()`方法,否则比较可能失败。 - **性能**:对于大型集合方法1(`equals()`)通常最快;方法3(HashMap)在元素复杂时更可靠。 - **避免`retainAll()`**:如引用[^2]指出,`retainAll()`用于求交集,不适合判断完全相等,因为它可能返回错误结果。 #### 4. **总结** - 优先使用`equals()`方法:如果集合有序且需顺序敏感。 - 使用排序HashMap:如果需忽略顺序处理自定义逻辑。 - 实际应用中,选择方法取决于具体场景。例如,数据库查询结果比较可能用方法2,而缓存数据验证可能用方法1。 如果您提供更多细节(如集合类型是否关心顺序),我可以给出更针对性的建议!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yuanzhengme

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值