首页 > 编程语言 >Java stream 中 peek() 的合理用法

Java stream 中 peek() 的合理用法

时间:2023-09-19 12:05:36浏览次数:36  
标签:peek Java stream 元素 terminal forEach 操作

目录

  • 背景
  • 最终操作(terminal operation)
  • peek() vs forEach()
  • peek() 的典型用法:协助调试
  • 小结
  • 参考链接

背景

这周遇到了一件很有意思的事情。在看项目代码时,发现了这么一段:

return objects.stream()
	       .peek(object -> addInfo(object, someParams))
	       .collect(Collectors.toList());
123

因为之前没接触过 peek(),这段代码看得我云里雾里。

后来在 这个链接 里读到这样一句话:

On top of that, peek() can be useful in another scenario: when we want to alter the inner state of an element.

翻译过来就是:

除此之外,peek() 还有另一种用途:改变元素的内部状态

这样一来,就不难理解上面代码的意图了:对每个 object 执行 addInfo(object, someParams),然后把结果收集到一个 List 里。

但后来又看了一些讨论,发现这个用法在这里虽然不算错,但并不是 peek() 最合理的用法。

最终操作(terminal operation)

为什么呢?因为 peek() 并不是一个最终操作(terminal operation)。出于性能考虑,stream 被设计为“元素只有在最终操作需要时才会被处理”。如果没有最终操作的“拉动”,那么 stream 中就没有操作会真正执行。

在上面的例子中,.collect(Collectors.toList()) 就是一个最终操作,而且这个操作会“拉动”所有元素。这样一来,每个元素都一定会被应用 peek() 方法,所以放在这里没有问题。

但在使用 peek() 时仍然需要注意,因为它只保证作用于流经管道的元素,但并不保证全部元素都会流经管道。

peek() vs forEach()

forEach() 则是一个最终操作。除此之外,peek()forEach() 再无其他不同。

顾名思义,forEach() 就是保证对 stream 里的每个元素都应用某个方法。如果这是你的意图,那么最好用 forEach() 而不是 peek(),这样代码会便于理解。如果上面的代码用的是 forEach(),那我一开始也不至于看不懂了。

peek() 的典型用法:协助调试

正因为 peek() 不是一个最终操作,不会影响“哪些元素会流过”,所以十分适合在调试的时候,用来打印出流经管道的元素。例如:

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());
123456

小结

  • 如果想对流经的每个元素应用一个函数,从而改变某些状态,那么请用 forEach()
  • 如果想打印流经的每个元素的状态(日志或 debug),这时应该用 peek()

参考链接

In Java streams is peek really only for debugging?Non-terminal forEach() in a stream?

标签:peek,Java,stream,元素,terminal,forEach,操作
From: https://blog.51cto.com/u_14299064/7523982

相关文章

  • Stream流处理快速上手最佳实践 | 京东物流技术团队
    一引言JAVA1.8得益于Lambda所带来的函数式编程,引入了一个全新的Stream流概念Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。......
  • 62基于java的高校奖学金管理系统设计与实现(可参考做毕业设计)
    本章节给大家带来一个基于java高校奖学金管理系统设计与实现,可适用于大学奖学金管理系统,学生奖学金管理系统,学校奖学金,校园奖学金申请管理系统;引言以往的高校奖学金管理系统相关信息管理,都是工作人员手工统计。这种方式不但时效性低,而且需要查找和变更的时候很不方便。随着科学......
  • 万字长文深度解读Java线程池,硬核源码分析
    前言本文将深入分析Java线程池的源码,包括线程池的创建、任务提交、工作线程的执行和线程池的关闭等过程。通过对线程池源码的解析,我们能够更好地理解线程池的原理和机制,为我们在实际开发中合理使用线程池提供指导。文章内容较长,建议找个安静的环境慢慢细读,由于线程池涉及的内容......
  • 常见的Java中SQL注解的用法
    @Select:用于查询操作,标注在方法上,指定相应的SQL查询语句。@Select("SELECT*FROMtable_nameWHEREcondition")List<Entity>getEntities();@Insert:用于插入操作,标注在方法上,指定相应的SQL插入语句@Insert("INSERTINTOtable_name(column1,column2)VALUES(#{value1}......
  • Java SE 基础
    Java美梦的交织来源于无数个光点--风尘尘风一、Java初识Java概述、Java特点、Java历史、Java体系、Java工具、Java组成1.1Java概述Java概念、Java之父、Java起名、Java图标、Java公司、Java由来1.Java概念Java概念:Java是一种流行的编程语言,创......
  • Java SE 扩展
    Java即使有一天一无所有,也不缺重新来的勇气!--做一场梦一、扩展知识原来知识真的可以让一个人废寝忘食--CF.FC1.1Java环境环境是基本也是基础,只有弄好它才能万丈高楼平地起--CF.FC第一步:下载JDK第二步:安装JDK第三步:配置JDK第四步:测试JDK......
  • Java8中遍历Map、Map转List、List转Map
    1.遍历MapMap<Integer,String>map=newHashMap<>();map.put(1,"a");map.put(2,"b");map.put(3,"c");//Map.keySet遍历for(Integerk:map.keySet()){ System.out.println(k+"==>"+map.get(k));......
  • Java并发Map的面试指南:线程安全数据结构的奥秘
    简介在计算机软件开发的世界里,多线程编程是一个重要且令人兴奋的领域。然而,与其引人入胜的潜力相伴而来的是复杂性和挑战,其中之一就是处理共享数据。当多个线程同时访问和修改共享数据时,很容易出现各种问题,如竞态条件和数据不一致性。本文将探讨如何在Java中有效地应对这些挑战,介......
  • Java并发Map的面试指南:线程安全数据结构的奥秘
    简介在计算机软件开发的世界里,多线程编程是一个重要且令人兴奋的领域。然而,与其引人入胜的潜力相伴而来的是复杂性和挑战,其中之一就是处理共享数据。当多个线程同时访问和修改共享数据时,很容易出现各种问题,如竞态条件和数据不一致性。本文将探讨如何在Java中有效地应对这些挑战,......
  • arcgis api for javascript 4.x, 删除绘制的点、线、面
    1、在视图mapView上添加的点线面//删除所有mapView.graphics.removeAll();//删除一个constpointGraphic=newGraphic({geometry,symbol})mapView.graphics.remove(pointGraphic);//删除多个mapView.graphics.removeMany([pointGraphic,polylineGraphic]);2、G......