簡體   English   中英

具有長度Comparator bug的Java TreeSet?

[英]Java TreeSet with length Comparator bug?

我有下面的代碼,它使用基於字符串長度的比較器創建一個TreeSet。

public class TreeSetComparator {
    public static void main(String[] args) {
        SortedSet<String> sortedSet = new TreeSet<>(Comparator.comparing(String::length));
        sortedSet.addAll(Arrays.asList("aa", "bb", "aa"));
        System.out.println(sortedSet);
    }
}

令我驚訝的是,上面的輸出是

[aa]

雖然我期待

[aa, bb]

要么

[bb, aa]

“bb”部分消失,這似乎與SortedSet合約相反。 比較器應該只對元素進行排序而不是確定它們的唯一性,這通常由等於確定。

另一方面,如果我將比較器增強為總是為不等於下面的項目返回非零,那么我才能得到正確的結果。

    SortedSet<String> sortedSet = new TreeSet<>(Comparator.comparing(String::length).reversed().thenComparing(String::toString));
    sortedSet.addAll(Arrays.asList("aa", "bb", "aa"));
    System.out.println(sortedSet);

現在的輸出是[aa, bb]正如我所料。

以上是TreeSet實現中的錯誤嗎?

我的環境如下:

mvn --version                                                                                                                                            21:40:22
Apache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-17T19:33:14+01:00)
Maven home: /home/aaaa/.sdkman/candidates/maven/current
Java version: 10.0.2, vendor: Oracle Corporation, runtime: /usr/lib/jvm/java-10-jdk
Default locale: en_GB, platform encoding: UTF-8
OS name: "linux", version: "4.14.60-1-manjaro", arch: "amd64", family: "unix"

UPDATE

以下是相關文章以及如何在未來版本的Java中解決問題的建議: https//yesday.github.io/blog/2018/java-gotchas-sorted-set-ignores-the-equals-method html的

這不是一個bug。 至少不在TreeSet

從javadoc,我的重點:

請注意,如果要正確實現Set接口,則由set維護的排序(無論是否提供顯式比較器)必須與equals一致 (有關與equals一致的精確定義,請參閱Comparable或Comparator。)這是因為Set接口是根據equals操作定義的,但TreeSet實例使用compareTo(或compare)方法執行所有元素比較,因此從集合的角度來看,通過這種方法被認為相等的元素是相等的 集合的行為即使其排序與equals不一致也是明確定義的; 它只是不遵守Set接口的一般合同。

因此,因為“aa”和“bb”都具有2的長度,所以它們被compareTo認為是相等的,因此被TreeSet認為是相等的。

根據定義與equals一致意味着:

當且僅當c.compare(e1,e2)== 0具有與每個e1的e1.equals(e2)相同的布爾值時,比較器c對一組元素S施加的排序被稱為與等於一致。和S中的e2

看起來他們假設比較器使用與equals方法相同的equals定義。 從SortedSet API:

請注意,如果有序集合要正確實現Set接口,則由有序集合維護的排序(無論是否提供顯式比較器)必須與equals一致。 (有關與equals一致的精確定義,請參閱Comparable接口或Comparator接口。)這是因為Set接口是根據equals操作定義的,但是有序集使用compareTo(或compare)方法執行所有元素比較因此,從排序集的角度來看,這種方法被認為相等的兩個元素是相等的。 即使排序與equals不一致,排序集的行為也是明確定義的; 它只是不遵守Set接口的一般合同。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM