【问题标题】:Stream and the distinct operation流和不同的操作
【发布时间】:2014-01-24 13:13:38
【问题描述】:

我有以下代码:

class C
{
    String n;

    C(String n)
    {
        this.n = n;
    }

    public String getN() { return n; }

    @Override
    public boolean equals(Object obj)
    {
        return this.getN().equals(((C)obj).getN());
    }
 }

List<C> cc = Arrays.asList(new C("ONE"), new C("TWO"), new C("ONE"));

System.out.println(cc.parallelStream().distinct().count());

但我不明白为什么 distinct 返回 3 而不是 2。

【问题讨论】:

  • 啊哈,您正在尝试使用 Java 8。也可以尝试在 C 类中覆盖 hashCode()。如果两个C 对象相等,那么它们的哈希码必须相同。
  • 在覆盖的equals 中放置一个断点,看看distinct 是否考虑它。
  • @Jesper,我在download.java.net/jdk8/docs/api/java/util/stream/… 的文档中没有看到任何关于hashcode 的担忧
  • 但它似乎最初在hashcode 上运行,因为这通常比equals 检查更有效。而且由于它是一个通用合约,两个相等的对象必须具有相同的哈希值。因此,仅当hashcodes 相同时才执行equals 检查是一个有效的解决方案。我相信这正是 distinct 所做的
  • 但我不明白为什么distinct返回3而不是2。distinct应该是count

标签: java java-8 java-stream


【解决方案1】:

您还需要覆盖C 类中的hashCode 方法。例如:

@Override
public int hashCode() {
    return n.hashCode();
}

当两个C 对象相等时,它们的hashCode 方法必须返回相同的值。

接口Stream的API文档没有提到这一点,但众所周知,如果你覆盖equals,你也应该覆盖hashCodeObject.equals() 的 API 文档提到了这一点:

请注意,当hashCode 方法被重写时,通常需要重写此方法,以维护hashCode 方法的一般约定,即相等的对象必须具有相等的哈希码。

显然,Stream.distinct() 确实使用了对象的哈希码,因为当你像我上面展示的那样实现它时,你会得到预期的结果:2。

【讨论】:

  • 可能在内部,流实现正在使用 HashSet,它利用了 hashCode 方法。
  • +1 您提到的规则非常重要,除非您同时覆盖两者,否则不要覆盖等于或哈希码。这可能会导致编译时错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-07
  • 1970-01-01
  • 2014-04-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多