您可以使用自定义收集器来执行此操作:
int posOfMax = stream.mapToInt(Set::size)
.collect(() -> new int[] { 0, -1, -1 },
(a,i) -> { int pos = a[0]++; if(i>a[2]) { a[1] = pos; a[2] = i; } },
(a1,a2) -> {
if(a2[2] > a1[2]) { a1[1] = a1[0]+a2[1]; a1[2] = a2[2]; }
a1[0] += a2[0];
})[1];
这是最轻量级的解决方案。当我们使用专用类而不是数组时,它的逻辑变得更加清晰:
int posOfMax = stream.mapToInt(Set::size)
.collect(() -> new Object() { int size = 0, pos = -1, max = -1; },
(o,i) -> { int pos = o.size++; if(i>o.max) { o.pos = pos; o.max = i; } },
(a,b) -> {
if(b.max > a.max) { a.pos = a.size+b.pos; a.max = b.max; }
a.size += b.size;
}).pos;
状态对象保存大小,它只是到目前为止遇到的元素数量、最后遇到的最大值及其位置,如果当前元素大于最大值,我们将其更新为先前的大小值。这就是累加器函数(第二个参数collect
) does.
为了支持任意评估顺序,即并行流,我们必须提供combiner函数(最后一个参数collect
)。它将两个部分评估的状态合并到第一个状态。如果第二个状态的最大值更大,我们更新第一个状态的最大值和位置,而我们必须将第一个状态的大小添加到第二个状态的位置以反映两者都是部分结果的事实。此外,我们必须将大小更新为两个大小的总和。