Collectors.toSet()是否总是返回HashSet?它的合同是什么?

11

Javadoc 表示:

返回一个收集器,它将输入元素累积到一个新的 Set 中。不能保证返回的 Set 的类型、可变性、可序列化性或线程安全性;如果需要更多对返回的 Set 的控制,请使用 toCollection(java.util.function.Supplier)。

因此,Collectors.toCollection(HashSet::new) 似乎是避免问题的好主意(SO question)。

我的问题是,尽管我已经尝试过很多次,但我仍然无法从 toSet() 返回除 HashSet 之外的任何其他东西

这里是我使用的代码:

public static void main(String[] args) {
    List<Integer> l = Arrays.asList(1,2,3);

    for (int i = 0 ; i++<1_000_000;){
        Class clazz = l.stream().collect(Collectors.toSet()).getClass();

        if (!clazz.equals(HashSet.class)) {
            System.out.println("Not a HashSet");
        }
    }
}

为什么Javadoc会声明没有保证,而实际上又确实存在保证呢...


11
目前HashSet::new是硬编码为返回Set的供应商(这解释了你的结果)。但是未来版本不保证不会更改此设置。 - Tunaki
3
为什么他们要做出保证?不明确行为规定可以让他们有自由更改,如果他们认为其他方式更好的话。 - resueman
2
@YassinHajaj 顺便说一下:i++<1_000_000;有点奇怪。当然,这很聪明,但它并没有比i < 1_000_000; i++更节省空间,而后者是大多数人倾向于使用的形式。如果你在一个与他人合作的项目中编码,我建议你尽量保持你的循环简单易懂。如果你是为自己编码,那就随意发挥吧。 - Jeffrey
6
JavaDoc主要关于规范说明,它说明了类或方法必须做什么以及用户可以依赖的内容。明确的规范与实现分离可以使读者受益,因为它告诉他们可以依靠什么,也可以使维护人员受益,因为它告诉他们对用户做出了哪些承诺(因此具有多少灵活性来发展或重新创建实现)。任何给定的实现几乎是定义好的,这就是为什么我们编写单独的规范说明的原因,这样你就不会依赖于实现的偶然特性。 - Brian Goetz
2
@Jeffrey:实际上,这两者并不相同。for(…; i++<1_000_000;)将处理值1_000_000,而for(…; i < 1_000_000; i++)则不会。这就是为什么应该避免使用这种不直观的结构,使用for(…; i <= 1_000_000; i++)更容易识别... - Holger
显示剩余6条评论
5个回答

15

JavaDoc文档说明没有保证,但这并不妨碍任何具体的实现始终返回特定类型的集合。这只是设计者说他们不想限制未来实现的可能性。它并没有说明当前实现实际上做了什么。

换句话说,你已经发现了实现定义的行为(总是返回HashSet),但如果你依赖于此,将来可能会遇到问题。


谢谢Jim。这确实是我没有想到的一种观点。我认为这里应该归咎于我的英语理解能力。 - Yassin Hajaj

5

当前的OpenJDK实现(据我所知,Oracle也是如此)确实总是返回一个HashSet - 但并没有保证。未来的JDK版本很可能会改变这种行为,并且如果你假设Collectors.toSet()会返回HashSet(例如,显式地向下转换),那么你的代码就会出错。


4
Collectors::toSet返回的Set类型是一个实现细节。您不应依赖于实现细节在未来版本中保持不变。当前,它们使用HashSet,但将来可能希望使用其他类型的集合。

4
未来的Java版本可能会返回专门的不可变集合实现,这些实现在读取时更加高效,消耗的内存比当前的HashSet实现少。这个实现实际上只是一个HashMap的包装器。Project valhalla可能最终会导致这样的优化。
它们甚至可以根据数据量返回不同的集合类型,例如,如果它事先知道只返回零个或一个元素,则返回空集或单例集。
因此,通过给出少于当前实现可能的保证,他们为未来的改进留下了空间。

1
我认为你需要的是这个: Collectors.toCollection(LinkedHashSet::new)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接