Nik*_*las 21 java comparator treeset java-8 java-11
同时使用 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]
Run Code Online (Sandbox Code Playgroud)
当我尝试删除 中存在的确切元素时TreeSet,它起作用了:所有指定的元素都被删除:
languages.removeAll(Arrays.asList("PYTHON", "C++"));
System.out.println(languages); // [java]
Run Code Online (Sandbox Code Playgroud)
但是,如果我尝试删除而不是 中存在的更多TreeSet,则调用根本不会删除任何内容(这不是后续调用,而是调用而不是上面的代码段):
languages.removeAll(Arrays.asList("PYTHON", "C++", "LISP"));
System.out.println(languages); // [c++, java, python]
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?为什么会这样?
编辑:String::compareToIgnoreCase是一个有效的比较器:
(l, r) -> l.compareToIgnoreCase(r)
Run Code Online (Sandbox Code Playgroud)
JB *_*zet 21
这是removeAll()的 javadoc :
此实现通过对每个集合调用 size 方法来确定此集合和指定集合中的较小者。如果此集合的元素较少,则实现将遍历此集合,依次检查迭代器返回的每个元素以查看它是否包含在指定的集合中。如果包含,则使用迭代器的 remove 方法将其从该集合中删除。如果指定集合的元素较少,则实现将迭代指定的集合,使用此集合的 remove 方法从此集合中删除迭代器返回的每个元素。
在您的第二个实验中,您处于 javadoc 的第一个案例中。因此它遍历“java”、“c++”等,并检查它们是否包含在由Set.of("PYTHON", "C++"). 他们不是,所以他们不会被删除。使用与参数相同的比较器使用另一个 TreeSet,它应该可以正常工作。使用两种不同的 Set 实现,一种使用equals(),另一种使用比较器,确实是一件危险的事情。
请注意,有一个关于此的错误:[JDK-8180409] TreeSet removeAll 与 String.CASE_INSENSITIVE_ORDER 不一致的行为。