【问题标题】:Java 8 Stream distinct is not workingJava 8 Stream distinct 不起作用
【发布时间】:2017-09-12 13:00:22
【问题描述】:

这就是我正在做的:

List scores = Stream.concat(oldEntries.stream(), newEntries.stream())
                    .sorted()
                    .distinct()
                    .limit(maxSize)
                    .collect(Collectors.toList());

我期待一个没有任何重复的排序列表,但有时列表中有重复。

我已经重写了 hashCode 和 equals 方法,我还观察到这些方法每次都返回正确的值。任何人都可以看到我的流有什么问题吗?

这是我的 equals() 和 hashCode() 它们是由 IDEA 自动生成的:

..
private int userId;
private int levelId;
private int score;

@Override
public boolean equals(Object o) {

    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Score score = (Score) o;

    if (userId != score.userId) return false;
    return levelId == score.levelId;

}

@Override
public int hashCode() {
    int result = userId;
    result = 31 * result + levelId;
    return result;
}

public int compareTo(Score other) {

    if (other == null) {
        return 1;
    } else {
        return Integer.compare(other.score, this.score);
    }
}

 ..

【问题讨论】:

  • 您的 equals/hashCode 可能没有正确实现。在问题中包含他们的代码。
  • 所以您声称您的代码是正确的,而distinct() 已损坏?
  • userIdlevelIdint?
  • compareTo中的代码怎么样?
  • @Eugene 我不明白为什么这是问题所在。 CompareTo 用于排序,而 hashCode 和 equals() 用于区分。 distinct 没有使用 compareTo。是吗?

标签: java java-8 java-stream


【解决方案1】:

这是一个错误。

Stream.distinct() 的文档简单地说:

返回由不同元素组成的流(根据 此流的Object.equals(Object))

对于有序流,不同元素的选择是稳定的(对于 重复元素,该元素首先出现在遭遇战中 顺序被保留。)对于无序流,没有稳定性保证 制作完成。

对于有序流,没有要求相等的对象应该紧挨着(连续地)出现。然而,实施似乎假设他们这样做。文档的意思是应该保留第一次出现的 user 2, level 3 而丢弃第二次出现的。

根据 Java 错误数据库,该错误一直存在到 Java 13 并且仍未解决。

链接

【讨论】:

  • 很好的发现。这是一个 catch-22,因为作为一个实现细节,它不能真正通过记录 hashCode/equals/compareTo 必须一致来解决。
【解决方案2】:

您的流首先根据compareTo 排序,即使用score

然后使用equals() 对其进行“区分”,即使用userIdlevelId。根据javadoc:

对于有序流,不同元素的选择是稳定的(对于 重复元素,该元素首先出现在遭遇战中 顺序被保留。)对于无序流,没有稳定性保证 制作完成。

例子:

score 1, user 2, level 3
score 3, user 2, level 3
score 1, user 3, level 1

排序后...

score 1, user 2, level 3
score 1, user 3, level 1
score 3, user 2, level 3

Distinct 现在什么都不做,因为根据用户/级别,元素不相等。这可能会导致“重复”元素,因为您是基于一个事物对流进行排序,但通过完全不同的事物来确定相等性。

【讨论】:

  • @MoienGK 因为流是排序流,所以假设相等的元素彼此跟随。在显示的示例中,情况并非如此,并且 distinct 无法删除得分为 3 的行,因为它不等于 before 它的行。
  • @ByeBye 你是什么意思?描述的很清楚。
  • @MoienGK 首先使用 distinct,而不是 sort
  • @Kayaman (for duplicated elements, the element appearing first in the encounter order is preserved.) 对我来说,这意味着始终保留第一个元素,而不是它会检查与它的邻居是否相等,在无序流中它可以是随机的
  • 优化的有效性在this answer 中得到了证明,但请注意,即使没有优化,也可能出现与equals 不一致的自然顺序的问题,例如当使用distinct() 而不使用sort() 时,因为在幕后使用的HashMap 使用自然顺序来解决哈希冲突(see here)...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-05
  • 1970-01-01
  • 2014-08-14
  • 2012-10-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多