[java] 커스텀 비교기를 사용하여 TreeSet에서 제거하지 않는 이유는 무엇입니까?

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입니다 .

이 구현은 각각에 대해 size 메소드를 호출하여이 세트와 지정된 콜렉션 중 작은 것을 결정합니다. 이 세트에 요소가 적은 경우, 구현은이 세트에 대해 반복되어, 반복자에 의해 돌려 주어진 각 요소가 차례로 지정된 컬렉션에 포함되어 있는지 확인합니다. 포함 된 경우 반복자의 remove 메소드를 사용하여이 세트에서 제거됩니다. 지정된 컬렉션에 요소가 적은 경우, 구현은 지정된 컬렉션을 반복하고,이 세트의 remove 메소드를 사용해, 반복자에 의해 돌려 주어진 각 요소를이 세트로부터 삭제합니다.

두 번째 실험에서는 javadoc의 첫 번째 경우입니다. 따라서 “java”, “c ++”등을 반복하여에 의해 반환 된 Set에 포함되어 있는지 확인합니다 Set.of("PYTHON", "C++"). 그것들은 제거되지 않았습니다. 인수와 동일한 비교자를 사용하여 다른 TreeSet을 사용하면 정상적으로 작동합니다. 하나는를 사용 equals()하고 다른 하나는 비교자를 사용하는 두 가지 다른 Set 구현을 사용하는 것은 실제로 위험한 일입니다.

참고 이것에 대해 열린 버그가 있다는 것을 : String.CASE_INSENSITIVE_ORDER와 [JDK-8180409] TreeSet의에서 removeAll 일관성없는 행동 .


답변