カスタムコンパレーターを使用してTreeSetから削除しないと、より大きな項目のセットが削除されないのはなぜですか?


22

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)

5
関連するバグエントリ:bugs.openjdk.java.net/browse/JDK-8180409(TreeSet removeAllがString.CASE_INSENSITIVE_ORDERで一貫性のない動作)
Progman

密接に関連するQ&A
ナマン

回答:


22

removeAll()の javadocは次のとおりです。

この実装は、それぞれのsizeメソッドを呼び出すことにより、このセットと指定されたコレクションのどちらが小さいかを判断します。このセットの要素が少ない場合、実装はこのセットを反復処理し、イテレータによって返された各要素を順番にチェックして、指定されたコレクションに含まれているかどうかを確認します。含まれている場合は、イテレータのremoveメソッドを使用してこのセットから削除されます。指定されたコレクションに含まれる要素が少ない場合、実装は指定されたコレクションを反復処理し、このセットのremoveメソッドを使用して、反復子によって返された各要素をこのセットから削除します。

2番目の実験では、javadocの最初のケースにいます。したがって、「java」、「c ++」などを反復処理し、それらがによって返されるセットに含まれているかどうかを確認しますSet.of("PYTHON", "C++")。そうではないので、削除されません。引数として同じコンパレーターを使用する別のTreeSetを使用すると、正常に機能するはずです。2つの異なるSet実装を使用して、1つはを使用equals()し、もう1つはコンパレータを使用して、実際に行うのは危険です。

これに関してバグが開かれていることに注意してください:[JDK-8180409] TreeSet removeAll String.CASE_INSENSITIVE_ORDERとの一貫性のない動作


両方のセットが同じ特性を持つとき、それは機能しますか? final Set<String> subLanguages = new TreeSet<>(String::compareToIgnoreCase); subLanguages.addAll(Arrays.asList("PYTHON", "C++", "LISP")); languages.removeAll(subLanguages);
ニコラス

1
javadocで説明されている「このセットに含まれる要素が少ない場合」に該当します。もう1つのケースは、「指定されたコレクションの要素が少ない場合」です。
JBニゼット

8
この答えは正しいですが、非常に直感に反する動作です。の設計上の欠陥のように感じTreeSetます。
Boann

同意しますが、それについては何もできません。
JBニゼット

4
それは両方です。正しく文書化されているのは非常に直感的ではない動作ですが、直感的でなく、だまされているため、いつか修正される可能性のある設計上のバグでもあります。
JB Nizet
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.