Java Stream处理顺序疑问:Map与ForEach为何交替执行?
为什么Java Streams的输出顺序和预期不一样?
先看你的代码:
List<Integer> l = new ArrayList<>(); l.add(0); l.add(1); l.add(2); l.add(3); l.add(4); l.add(4); l.stream() .distinct() .map(v -> { System.out.println("In Map " + v); return v; }) .forEach(v -> { System.out.println("In ForEach " + v); });
你的预期输出是先打印所有In Map,再打印所有In ForEach,但实际是每个元素先走完map再进入forEach,原因很简单:
Java Stream是「元素驱动的流水线」,不是批量处理
Stream的中间操作(比如distinct、map)都是惰性求值的——它们不会立刻执行,只有当终端操作(比如forEach)需要元素时,才会从上游一步步拉取元素,逐个走完整个操作链。
具体到你的代码,执行流程是这样的:
forEach需要第一个元素,于是从源列表拉取0,经过distinct(没出现过,保留),执行map里的打印In Map 0,返回0,然后forEach打印In ForEach 0。- 第一个元素处理完,
forEach需要第二个元素,拉取1,重复上面的流程:distinct保留→map打印→forEach打印。 - 以此类推,直到处理完
4(第二个4会被distinct过滤掉,不会进入后续操作)。
你之所以会有预期的批量输出,是误以为Stream会先把所有元素都执行完前面的中间操作,再统一传给终端操作,但这不符合Stream的设计逻辑——Stream的这种逐个处理的方式,能减少内存占用(不需要把所有中间结果都存起来),尤其是处理大集合的时候优势很明显。
补充个小知识点:如果中间操作是有状态的聚合操作(比如sorted()),那它会先收集所有元素完成排序,再逐个传给下游,但distinct()虽然也是有状态(需要记录已出现的元素),但它还是逐个处理元素,遇到重复的就直接跳过,不会等到所有元素都收集完再处理。
内容的提问来源于stack exchange,提问作者Arun Kumar V
相关产品推荐
相关产品推荐

