首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >有长度比较器错误的Java TreeSet?

有长度比较器错误的Java TreeSet?
EN

Stack Overflow用户
提问于 2018-08-09 04:43:01
回答 2查看 594关注 0票数 5

我有下面的代码,它使用基于字符串长度的比较器来创建TreeSet。

代码语言:javascript
复制
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);
    }
}

令我惊讶的是,上面的输出是

代码语言:javascript
复制
[aa]

虽然我期待着

代码语言:javascript
复制
[aa, bb]

代码语言:javascript
复制
[bb, aa]

"bb“部分消失,这似乎与SortedSet合约相悖.比较器应该只对元素进行排序,而不确定它们的唯一性,这通常是由equals确定的。

另一方面,如果我增强比较器,使不相等的项总是返回非零值,就像下面这样,只有这样我才能得到正确的结果。

代码语言:javascript
复制
    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实现中的错误吗?

我的环境如下:

代码语言:javascript
复制
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"

更新

这里有一个相关的帖子,以及关于如何在未来的Java版本中解决这个问题的建议:https://yesday.github.io/blog/2018/java-gotchas-sorted-set-ignores-the-equals-method.html

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-08-09 04:46:15

这不是一个bug。至少在TreeSet中不是。

在javadoc中,我强调:

请注意,如果要正确实现set接口,则Set维护的排序(无论是否提供显式比较器)必须与equals一致。(有关与等于一致的精确定义,请参阅可比较或比较程序。)这是因为set接口是根据equals操作定义的,但是比较一个TreeSet实例使用其compareTo (或)方法执行所有元素比较,因此从Set的角度来看,此方法认为相等的两个元素等于。set的行为是明确定义的,即使它的顺序与equals不一致;它只是没有遵守Set接口的通用约定。

因此,因为"aa“和"bb”的长度都是2,所以compareTo认为它们相等,因此TreeSet也认为它们相等。

By definition,与equals一致意味着:

当且仅当c.compare( e1,e2)==0具有与e1.equals( e2 )相同的布尔值时,比较器c对一组元素S的排序与等于一致。对于S中的每个e1和e2,equals (E2)。

票数 16
EN

Stack Overflow用户

发布于 2018-08-09 04:49:30

看起来他们假设比较器使用与equals方法相同的equals定义。在SortedSet应用编程接口中:

请注意,如果排序集要正确实现set接口,则排序集维护的排序(无论是否提供显式比较器)必须与equals一致。(有关与等于一致的精确定义,请参阅可比较的接口或比较器接口。)这是因为集合接口是按照等于操作定义的,但是排序集合使用它的compareTo (或compare)方法执行所有元素比较,因此从排序集合的角度来看,该方法认为相等的两个元素是相等的。排序集的行为是明确定义的,即使它的排序与等号不一致;它只是不遵守set接口的通用约定。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51755344

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档