同时使用Java 8和Java 11,将以下 TreeSet
与 String::compareToIgnoreCase
比较器一起考虑:
final Set<String> languages = new TreeSet<>(String::compareToIgnoreCase);
languages.add("java");
languages.add("c++");
languages.add("python");
System.out.println(languages); // [c++, java, python]
当我尝试删除
TreeSet
中存在的确切元素时,它起作用:所有指定的元素均被删除:languages.removeAll(Arrays.asList("PYTHON", "C++"));
System.out.println(languages); // [java]
但是,如果我尝试删除的大于
TreeSet
中存在的,则该调用根本不会删除任何内容(这不是后续调用,而是被调用而不是上面的代码段):languages.removeAll(Arrays.asList("PYTHON", "C++", "LISP"));
System.out.println(languages); // [c++, java, python]
我究竟做错了什么?为什么会这样呢?
编辑:
String::compareToIgnoreCase
是有效的比较器:(l, r) -> l.compareToIgnoreCase(r)
最佳答案
这是removeAll()的javadoc:
This implementation determines which is the smaller of this set and the specified collection, by invoking the size method on each. If this set has fewer elements, then the implementation iterates over this set, checking each element returned by the iterator in turn to see if it is contained in the specified collection. If it is so contained, it is removed from this set with the iterator's remove method. If the specified collection has fewer elements, then the implementation iterates over the specified collection, removing from this set each element returned by the iterator, using this set's remove method.
在您的第二个实验中,您遇到的是Javadoc的第一种情况。因此,它将遍历“java”,“c++”等,并检查它们是否包含在
Set.of("PYTHON", "C++")
返回的Set中。它们不是,因此不会被删除。使用另一个TreeSet,使用与参数相同的比较器,它应该可以正常工作。
使用两种不同的Set实现,一种使用
equals()
,另一种使用比较器,确实是一件危险的事情。请注意,有关此的错误已打开:[JDK-8180409] TreeSet removeAll inconsistent behaviour with String.CASE_INSENSITIVE_ORDER。
关于java - 为什么不使用自定义比较器从TreeSet中删除,则会删除较大的项集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59553029/