Collectors.toSet() 总是 return 一个 HashSet 吗?合约是什么?

Does Collectors.toSet() always return a HashSet ? What is the contract?

Javadoc 说

Returns a Collector that accumulates the input elements into a new Set. There are no guarantees on the type, mutability, serializability, or thread-safety of the Set returned; if more control over the returned Set is required, use toCollection(java.util.function.Supplier).

所以 Collectors.toCollection(HashSet::new) 似乎是避免此处出现问题的好主意 ()。

我的问题是,尽我所能,除了 HashSet

,我无法从 toSet() 得到任何其他返回值

这是我使用的代码:

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 声明没有保证,而事实上,有...

JavaDoc 声明没有保证,但这并不妨碍任何特定的实现总是return特定类型的集合。这只是设计人员说他们不想限制未来实现的功能。它没有说明当前的实现实际上做了什么。

换句话说,您发现了实现定义的行为(总是return一个HashSet),但如果您指望它,您可能会遇到问题将来。

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

当前 OpenJDK 的实现(以及 AFAIK,Oracle 的也是)确实总是 returns a HashSet - 但没有 保证 的那个。如果您以某种方式假设 Collectors.toSet() 将 return 变成 HashSet(例如,显式向下转换它),JDK 的未来版本很可能会改变这种行为并破坏您的代码).

我想你要找的是这个: Collectors.toCollection(LinkedHashSet::new)

例如,

未来的 java 版本可能 return 专门的不可变集实现比当前的 HashSet 实现更高效地读取并且消耗更少的内存,这实际上只是HashMap 的包装器。 Project valhalla 最终可能会导致此类优化。

他们甚至可能会根据数据量选择 return 不同的集合类型,例如如果事先知道只有零个或一个元素将被 returned.

,则为空集或单例集

因此,通过提供比基于当前实施的可能更少的保证,他们为未来的改进敞开了大门。