Korzystając zarówno z Java 8, jak i Java 11, weź pod uwagę następujące kwestie TreeSet
z String::compareToIgnoreCase
komparatorem:
final Set<String> languages = new TreeSet<>(String::compareToIgnoreCase);
languages.add("java");
languages.add("c++");
languages.add("python");
System.out.println(languages); // [c++, java, python]
Kiedy próbuję usunąć dokładne elementy znajdujące się w TreeSet
, to działa: wszystkie te określone są usuwane:
languages.removeAll(Arrays.asList("PYTHON", "C++"));
System.out.println(languages); // [java]
Jeśli jednak spróbuję usunąć więcej, niż jest w TreeSet
, wywołanie w ogóle niczego nie usunie (nie jest to kolejne wywołanie, ale wywołane zamiast fragmentu powyżej):
languages.removeAll(Arrays.asList("PYTHON", "C++", "LISP"));
System.out.println(languages); // [c++, java, python]
Co ja robię źle? Dlaczego tak się zachowuje?
Edycja: String::compareToIgnoreCase
jest poprawnym komparatorem:
(l, r) -> l.compareToIgnoreCase(r)
Odpowiedzi:
Oto javadoc z removeAll () :
W drugim eksperymencie jesteś w pierwszym przypadku javadoc. I tak iteruje po „java”, „c ++” itd. I sprawdza, czy są one zawarte w zestawie zwróconym przez
Set.of("PYTHON", "C++")
. Nie są, więc nie są usuwane. Użyj innego TreeSet, używając tego samego komparatora jako argumentu, i powinno działać dobrze. Korzystanie z dwóch różnych implementacji zestawu, z których jedna korzystaequals()
, a druga komparatora, jest naprawdę niebezpieczna.Zauważ, że został otwarty błąd dotyczący tego: [JDK-8180409] TreeSet removeWszystkie niespójne zachowanie z String.CASE_INSENSITIVE_ORDER .
źródło
final Set<String> subLanguages = new TreeSet<>(String::compareToIgnoreCase);
subLanguages.addAll(Arrays.asList("PYTHON", "C++", "LISP"));
languages.removeAll(subLanguages);
TreeSet
.