集合中 removeAll 方法的不直观行为 [英] Unintuitive behavior of removeAll method in sets

查看:42
本文介绍了集合中 removeAll 方法的不直观行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用单个 Comparator 时发现了 AbstractSetsremoveAll 方法的这种奇怪行为.

I discovered this weird behavior of the removeAll method of AbstractSets when working with individual Comparators.

根据比较集合的大小,使用不同的比较器.

Depending on the size of the compared collections a different comparator is used.

它实际上记录在 API 中,但我仍然看不到其背后的原因.

It is actually documented in the API but I still cannot see the reason behind it.

代码如下:

import java.util.Comparator;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;

public class Test {
    public static void main(String[] args) {
        // Any comparator. For this example, the length of a string is compared
        Set<String> set = new TreeSet<String>(new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                        return o1.length() - o2.length();
                }
        });

        set.add("a");
        set.add("aa");
        set.add("aaa");
        set.add("aaaa");
        System.out.println(set); // output: [a, aa, aaa, aaaa]

        Stack<String> stack = new Stack<String>();
        stack.push("b");
        stack.push("bb");
        stack.push("bbb");
        stack.push("bbbb");

        set.removeAll(stack); // NO ITEMS ARE REMOVED from the set
        System.out.println(set); // output: [a, aa, aaa, aaaa]

        // Now let's see what happens if I remove an object from the stack
        stack.pop();
        set.removeAll(stack); // ALL ITEMS from the stack are removed from the
                                                        // set
        System.out.println(set); // output: [aaaa]

        /* Reason for this strange behaviour: Depending on the size of the
         * passed Collection, TreeSet uses either the remove() function of
         * itself, or from the Collection object that was passed. While the
         * remove() method of the TreeSet uses the comparator to determine
         * equality, the remove() method of the passed usually determines
         * equality by calling equals() on its objects.
         */
    }
}

这是 JavaDoc.

推荐答案

您基本上创建了未定义的行为,因为您的集合具有不同的相等标准.以任何方式组合集合只有在它们具有相同的情况下才能起作用.您基本上违反了 A.equals(B) 必须产生与 B.equals(A) 相同的结果的约定.

You have basically created undefined behavior since your sets have different criteria of equality. Combining collections in any way can only work if they have the same. You are basically violating the contract that A.equals(B) must yield the same result as B.equals(A).

可比:强烈推荐(虽然不是必需的)自然顺序与 equals 一致.之所以如此,是因为没有显式比较器的排序集(和排序映射)在与自然顺序与 equals 不一致的元素(或键)一起使用时表现得奇怪".特别是,这样的排序集合(或排序映射)违反了集合(或映射)的一般约定,后者是根据 equals 方法定义的.

Comparable: It is strongly recommended (though not required) that natural orderings be consistent with equals. This is so because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of the equals method.

这篇关于集合中 removeAll 方法的不直观行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆