繁体   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