![](/img/trans.png)
[英]My treemap breaks after sorting it because “comparator used for the treemap is inconsistent with equals”
[英]Case-insensitive Comparator breaks my TreeMap
我在TreeMap
使用的Comparator
破壞了我對TreeMap
預期行為。 看下面的代碼:
TreeMap<String, String> treeMap = new TreeMap<>(new Comparator<String>() {
public int compare(String o1, String o2) {
return o1.toLowerCase().compareTo(o2.toLowerCase());
}
});
treeMap.put("abc", "Element1");
treeMap.put("ABC", "Element2");
我認為我所做的是我創建了一個按鍵排序的地圖,不區分大小寫。 兩個不同的元素具有不相等的鍵( abc
和ABC
),其比較將返回0
。 我期待這兩個元素的隨機排序。 然而,命令:
System.out.println("treeMap: " + treeMap);
導致:
treeMap: {abc=Element2}
鍵abc
已重新賦值Element2
!
任何人都可以解釋這是如何發生的,如果它是一個有效的,記錄的TreeMap
行為?
這是因為如果a.compareTo(b) == 0
TreeMap
認為元素相等。 它在JavaDoc for TreeMap (強調我的)中有記錄:
請注意,如果此有序映射要正確實現Map接口,則樹映射維護的順序(如任何有序映射)以及是否提供顯式比較器必須與
equals
一致 。 (見Comparable
或Comparator
為一致的精確定義與equals
)。這是因為Map接口在來定義equals
的操作,但有序映射使用它的執行所有的鍵比較compareTo
(或compare
)方法,於是兩個從排序映射的角度來看, 通過此方法被視為相等的鍵是 相等的 。 即使排序與equals
不一致,也可以很好地定義有序映射的行為。 它只是不遵守Map接口的一般合同。
你的比較器與equals不一致。
如果你想保持不等於但等於忽略大小的元素,那么對你的比較器進行第二級檢查,使用區分大小寫的順序:
public int compare(String o1, String o2) {
int cmp = o1.compareToIgnoreCase(o2);
if (cmp != 0) return cmp;
return o1.compareTo(o2);
}
傳遞給TreeMap
的Comparator
不僅確定了Map
內部鍵的順序,還確定兩個鍵是否被認為是相同的(當compare()
返回0
時它們被認為是相同的)。
因此,在您的TreeMap
,“abc”和“ABC”被視為相同的鍵。 Map
s不允許相同的鍵,因此第二個值Element2
覆蓋第一個值Element1
。
您需要確保該映射元素的相等性與比較器一致。 引用課堂評論:
請注意,如果此有序映射要正確實現接口,則樹映射維護的排序(如任何已排序的映射,以及是否提供顯式比較器)必須與equals一致。
接受的答案在技術上是正確的,但錯過了解決問題的慣用方法。
您應該使用提供的靜態String.CASE_INSENSITIVE_ORDER
比較器或至少使用自己內部的String.compareToIgnoreCase()
來考慮.equal()
。
對於區域設置敏感的比較,您應該使用java.text.Collator
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.