個人を扱うときのremoveAll
メソッドのこの奇妙な動作を発見しました。AbstractSets
Comparators
比較されるコレクションのサイズに応じて、異なるコンパレータが使用されます。
実際には API で文書化されていますが、その背後にある理由はまだわかりません。
コードは次のとおりです。
import java.util.Comparator;
import java.util.Set;
import java.util.Stack;
import java.util.TreeSet;
public class Test {
public static void main(String[] args) {
// Any comparator. For this example, the length of a string is compared
Set<String> set = new TreeSet<String>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
set.add("a");
set.add("aa");
set.add("aaa");
set.add("aaaa");
System.out.println(set); // output: [a, aa, aaa, aaaa]
Stack<String> stack = new Stack<String>();
stack.push("b");
stack.push("bb");
stack.push("bbb");
stack.push("bbbb");
set.removeAll(stack); // NO ITEMS ARE REMOVED from the set
System.out.println(set); // output: [a, aa, aaa, aaaa]
// Now let's see what happens if I remove an object from the stack
stack.pop();
set.removeAll(stack); // ALL ITEMS from the stack are removed from the
// set
System.out.println(set); // output: [aaaa]
/* Reason for this strange behaviour: Depending on the size of the
* passed Collection, TreeSet uses either the remove() function of
* itself, or from the Collection object that was passed. While the
* remove() method of the TreeSet uses the comparator to determine
* equality, the remove() method of the passed usually determines
* equality by calling equals() on its objects.
*/
}
}