这个概念(将 2 个长度相等的流混合在一起,这样您最终会从每个流中获取一个元素,都传递给一个函数,然后将该组合映射到其他东西)称为 zipping。
Java 的流类不包含对此操作的任何支持。你在这里拥有的东西也不是你可以有意义地压缩在一起的东西,除非你能以某种方式保证两者都会以完全相同的顺序发生这个“id”概念(即,如果你的sizes 是[{3, large}, {2, small}] 而不是,我们是不再谈论 zip 操作)。
在前一种情况下(这不是关于'组合红色和小,因为它们都有 id 2,而是关于组合 colors 中第一个元素的 2 和 red 与来自 small sizes 中的第一个元素,无论 id 是什么),你可以从另一个库中找到 zip 支持,或者破解它:
if (colors.size() != sizes.size()) throw new IllegalStateException();
IntStream.range(0, colors.size())
.mapToObj(i -> new Thing(colors.get(i).getId(), colors.get(i).getColor(), sizes.get(i).getSize()))
.collect(Collectors.toList());
它看起来很难看,如果列表不是随机访问,它的性能会非常糟糕,在几乎所有方面我都可以理解,与只创建 2 个迭代器并并行迭代它们相比,这真是令人失望:
if (colors.size() != sizes.size()) throw new IllegalStateException();
var itColors = colors.iterator();
var itSizes = sizes.iterator();
var out = new ArrayList<Thing>();
while (itColors.hasNext()) {
Thing a = itColors.next();
out.add(new Thing(a.getId(), a.getColor(), itSizes.next().getSize());
}
如果你想以这种方式处理它,你绝对不应该首先使用流。
不,是关于 ID。
在这种情况下,溪流看起来很像你用一把非常闪亮的花哨的锤子在三明治上涂抹果酱:溪流只是……在这里毫无意义。完全没有。你可以尝试一些 hacky 怪人的东西,好吧,实现这一点并使用流,但它会是片状代码:它看起来很奇怪,是非惯用的,包含大量警告(假设,如果不是真的,意味着代码无法正确完成工作,或者在某些情况下具有极差的性能特征),并且通常会变得更糟。
解决方案是地图:
var out = new HashMap<Long, Thing>();
for (Thing c : colors) out.put(c.getId(), c);
for (Thing s : sizes) out.merge(c.getId(), s,
(a, b) -> new Thing(a.getId(), a.getColor(), b.getSize());
看看它有多干净,它还可以处理输入之间的任何不匹配(大小包含 id 87,但颜色不包含)。