Java Stream.iterate传入偶数校验谓词时仅输出0的问题
问题核心原因
你对三参数Stream.iterate的方法逻辑理解有误。
Java 9新增的三参数Stream.iterate方法签名为Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next),它的执行逻辑和普通for循环完全等价:
- 初始化当前值为传入的种子值
seed - 对当前值执行
hasNext谓词判断:返回false则直接终止整个流,不再生成任何元素;返回true则将当前值加入流 - 对当前值应用
next函数计算得到下一个值,回到步骤2重复判断
注意:hasNext是流的终止条件,不是元素过滤条件——它不会跳过不符合条件的元素,只要遇到不满足谓词的值,整个流会直接结束。
把你的第一版代码等价替换为for循环就能立刻看到问题:
// 和你的第一版Stream代码逻辑完全一致 for(int s = 0; ((s<10) && (s%2==0)); s = s+1) { System.out.println(s); }
这段for循环运行后本来就只会打印0:初始s=0满足条件,打印后s自增为1,此时判断条件(1<10) && (1%2==0)返回false,循环直接终止。
你的三段代码运行结果对应解释
- 带偶数校验的初始版本:输出0后下一个值为1,不满足
hasNext谓词,流直接终止,仅打印0 - 移除偶数校验的版本:
hasNext仅判断s<10,0-9均满足条件,到s=10时判断不满足终止流,因此正常打印0-9 - 仅保留偶数校验加
limit(10)的版本:输出0后下一个值为1,不满足s%2==0的终止判断,流直接终止,limit操作根本拿不到后续元素,因此仍然只打印0
正确实现偶数流的写法
写法1:调整递进步长直接生成偶数
不需要额外过滤,每次递增加2,hasNext仅保留边界判断即可,性能最优:
Stream<Integer> stream = Stream.iterate(0, s -> s < 10, s -> s + 2); stream.forEach(System.out::println); // 输出结果:0、2、4、6、8
写法2:生成连续序列后过滤
如果递推逻辑无法直接跳过不符合要求的元素,可以先生成连续序列,再通过filter完成元素筛选:
Stream<Integer> stream = Stream.iterate(0, s -> s < 10, s -> s + 1) .filter(s -> s % 2 == 0); stream.forEach(System.out::println);
内容的提问来源于stack exchange,提问作者Amit Saha
相关产品推荐
相关产品推荐

