[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 일관성없는 행동 .