java如何以与List相同的方式计算流的哈希代码。hashCode()
我刚刚意识到,使用Stream.reduce(...)实现以下算法来计算流的哈希代码是不可能的。问题是哈希代码的初始种子是1
,这不是累加器的标识
关于List.hashCode()的算法 :
int hashCode = 1;
for (E e : list)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
您可能会认为以下内容是正确的,但事实并非如此,尽管如果不拆分流处理,它将起作用
List<Object> list = Arrays.asList(1,null, new Object(),4,5,6);
int hashCode = list.stream().map(Objects::hashCode).reduce(1, (a, b) -> 31 * a + b);
似乎唯一明智的方法是获取Stream
的Iterator
并进行正常的顺序处理或首先将其收集到List
# 1 楼答案
Holger写对了solution,如果你想要一个简单的方法,还有两种可能性:
一,。收集到
List
并呼叫hashCode()
二,。使用
Stream.iterator()
提醒一下
List.hashCode()
使用的算法:# 2 楼答案
作为第一种方法,我会使用collect-to-a-list解决方案,只要您不担心性能问题。这样你就避免了重新实现轮子,如果有一天哈希算法发生了变化,你就会从中受益,如果流是并行的,你也会安全(即使我不确定这是不是一个真正的问题)
我实现它的方式可能会有所不同,这取决于您需要如何以及何时比较不同的数据结构(我们称之为^{)
如果手动且少量地执行此操作,一个简单的静态功能可能就足够了:
像这样使用它
但是,如果
Foo
的实例本身存储在Collection
中,并且需要同时实现hashCode()
和equals()
(来自Object
),我会将其包装在FooEqualable
中:我完全知道,如果对
hashCode()
和equals()
进行多次调用,这个解决方案不会优化(性能方面),但我倾向于不优化,除非它成为一个问题# 3 楼答案
我找到的最简单、最短的方法是使用
Collectors.reducing
实现Collector
:# 4 楼答案
虽然乍一看,哈希代码算法由于其非关联性似乎是不可并行的,但如果我们转换函数,它是可能的:
到
这基本上是
或者对于大小为
n
的任意List
:第一个
1
是原始算法的初始值,eₓ
是索引x
处列表元素的哈希代码。虽然求和现在是独立于求值顺序的,但显然存在对元素位置的依赖性,我们可以首先通过对索引进行流式处理来解决这个问题,这适用于随机访问列表和数组,或者通常使用跟踪遇到对象数目的收集器来解决。收集器可以使用重复乘法进行累加,并且只能使用幂函数来组合结果: