java - 使用 Java 8 Streams API,在调用 Collectors.toSet() 时是否可以依赖 sorted()?

标签 java collections java-8 java-stream

这是 java.util.stream.Collectors 类的 toSet() 方法的实现:

public static <T>
Collector<T, ?, Set<T>> toSet() {
    return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
                               (left, right) -> { left.addAll(right); return left; },
                               CH_UNORDERED_ID);
}

正如我们所见,它使用了一个HashSet 并调用了add。来自 HashSet documentation , “它不保证集合的迭代顺序;特别是,它不保证顺序将随着时间的推移保持不变。”

在下面的代码中,StringList 被流式传输、排序并收集到 Set 中:

public static void main(String[] args) {
    Set<String> strings = Arrays.asList("c", "a", "b")
            .stream()
            .sorted()
            .collect(Collectors.toSet());
    System.out.println(strings.getClass());
    System.out.println(strings);
}

这提供了输出:

类 java.util.HashSet

[a, b, c]

输出已排序。我认为这里发生的事情是,虽然 HashSet 文档提供的契约(Contract)指定排序不是它提供的东西,但实现恰好按顺序添加。我想这可能会在未来的版本中发生变化/在 JVM 之间有所不同,并且更明智的方法是执行类似 Collectors.toCollection(TreeSet::new) 的操作。

调用Collectors.toSet()时可以依赖sorted()吗?

此外,“它不保证订单会随着时间的推移保持不变”到底是什么意思? (我想 addremove,底层数组的大小调整?)

最佳答案

要回答这个问题,您必须对 HashSet 的实现方式有所了解。顾名思义,HashSet 是使用哈希表 实现的。基本上,哈希表是一个由元素哈希索引的数组。哈希函数(在 Java 中,对象的哈希值由 object.hashCode() 计算)基本上是一个满足几个条件的函数:

  • (相对)快速计算给定元素
  • .equals() 彼此具有相同哈希值的两个对象
  • 不同项目具有相同哈希值的可能性很低

因此,当您遇到一个“已排序”(理解为“迭代器保留元素的自然顺序”)的 HashSet 时,这是由于几个巧合:

  • 元素的自然顺序遵循其hashCode的自然顺序
  • 哈希表足够小,不会发生冲突(具有相同哈希码的两个元素)

如果查看 String 类的 hashCode() 方法,您会发现对于单字母字符串,哈希码对应于 Unicode 索引(代码点)字母的 - 所以在这种特定情况下,只要哈希表足够小,元素就会被排序。然而,这是一个巨大的巧合和

  • 不适用于任何其他排序顺序
  • 对于 hashCode 不遵循其自然顺序的类不成立
  • 不会持有冲突的哈希表

此外,这与 sorted() 在流上被调用这一事实无关 - 这仅仅是由于 hashCode() 的实现方式和因此哈希表的顺序。因此,问题的简单答案是“否”。

关于java - 使用 Java 8 Streams API,在调用 Collectors.toSet() 时是否可以依赖 sorted()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46857619/

相关文章:

java - 使用 Java NIO 重命名非空目录问题

java - LibGDX 3D 提高性能

java - 上下文无法解析为类型

java - 将 A<X,Y> 类型转换为 A<Object,Object>

collections - 如何在特定索引中添加新项目?

java - 为什么 containsAll 在第二种情况下确实返回 true

java - 在 List 上调用 .sort 时出现 AbstractList UnsupportedOperationException

java - 每个具有单个抽象方法的接口(interface)都应该是函数式接口(interface)吗?

java - 如何获取ArrayList中重复的对象?

Java数组记录