forEach 方法接收一个 Lambda 表达式,而后在 Stream 的每个元素上执行该表达式。java
清单 打印姓名(forEach 和 pre-java8 的对比)api
1多线程 2app 3函数 4性能 5优化 6线程 7设计 8code 9 10 |
// Java 8 roster.stream() .filter(p -> p.getGender() == Person.Sex.MALE) .forEach(p -> System.out.println(p.getName())); // Pre-Java 8 for (Person p : roster) { if (p.getGender() == Person.Sex.MALE) { System.out.println(p.getName()); } } |
对一我的员集合遍历,找出男性并打印姓名。能够看出来,forEach 是为 Lambda 而设计的,保持了最紧凑的风格。并且 Lambda 表达式自己是能够重用的,很是方便。当须要为多核系统优化时,能够 parallelStream().forEach(),只是此时原有元素的次序无法保证,并行的状况下将改变串行时操做的行为,此时 forEach 自己的实现不须要调整,而 Java8 之前的 for 循环 code 可能须要加入额外的多线程逻辑。
但通常认为,forEach 和常规 for 循环的差别不涉及到性能,它们仅仅是函数式风格与传统 Java 风格的差异。
另一点须要注意,forEach 是 terminal 操做,所以它执行后,Stream 的元素就被“消费”掉了,你没法对一个 Stream 进行两次 terminal 运算。下面的代码是错误的:
1 2 |
stream.forEach(element -> doOneThing(element)); stream.forEach(element -> doAnotherThing(element)); |
相反,具备类似功能的 intermediate 操做 peek 能够达到上述目的。以下是出如今该 api javadoc 上的一个示例。
清单 peek 对每一个元素执行操做并返回一个新的 Stream
1 2 3 4 5 6 |
Stream.of("one", "two", "three", "four") .filter(e -> e.length() > 3) .peek(e -> System.out.println("Filtered value: " + e)) .map(String::toUpperCase) .peek(e -> System.out.println("Mapped value: " + e)) .collect(Collectors.toList()); |
forEach 不能修改本身包含的本地变量值,也不能用 break/return 之类的关键字提早结束循环。