Java 8 Stream中filter内添加元素到列表无结果的原因咨询
这是个很典型的Java Stream新手误区——你忽略了Stream的惰性求值机制,这也是第一种写法没有任何输出的核心原因。
先搞懂Stream的操作分类
Java Stream的操作分为两类:
- 中间操作:比如
filter、map、flatMap这些,它们只是用来构建流的处理管道,不会立即执行任何实际的遍历或计算。你可以把它们理解为“定义规则”,但还没真正动手干活。 - 终端操作:比如
collect、forEach、count、findFirst这些,它们才会触发整个流的遍历和处理,让之前定义的中间操作规则真正生效。
分析你的三种代码情况
第一种写法(仅调用
filter):
你只调用了stream().filter(...),但没有添加任何终端操作。这时候Stream只是构建了一个处理管道,根本没有开始遍历datas.entrySet(),所以filter里的代码(包括matcher.matches()和results.add(...))完全没有执行,results自然是空列表。第二种写法(用
collect):collect(Collectors.toList())是一个终端操作,它会触发Stream遍历所有元素,逐个执行filter里的判断逻辑。这时候符合条件的元素会被保留,同时你在filter里的results.add(...)也会被执行,所以results被正确填充,同时collect也返回了符合条件的entry列表。第三种写法(用
forEach):forEach同样是终端操作,它会遍历所有经过filter过滤后的元素,触发filter逻辑执行,所以results被填充,同时forEach里的打印语句也输出了对应的key。
额外建议:避免在中间操作里产生副作用
你在filter里修改外部集合results的做法其实不符合Stream设计理念,属于“副作用”操作,容易引发线程安全问题(如果是并行流的话),也会让代码可读性变差。更优雅的写法应该是直接用Stream的操作提取你需要的position,然后收集到列表里:
Map<String,String> datas = new HashMap<>(); // 初始化datas的代码省略... String expression = "Value_#Position#_1"; Pattern pattern = Pattern.compile(expression.replaceAll("#Position#","(?<position>.*)")); List<String> results = datas.entrySet().stream() .map(entry -> pattern.matcher(entry.getKey())) .filter(Matcher::matches) .map(matcher -> matcher.group("position")) .collect(Collectors.toList()); System.out.println(results); // 输出 [005, 001, 003]
这种写法完全依赖Stream的流水线操作,没有外部副作用,代码更简洁也更符合函数式编程的风格。
内容的提问来源于stack exchange,提问作者tweetysat

