Stream的终极技巧分享,一步帮你高效处理数据,阿里的大牛都在用

我用 Python 监听了自己的键盘,生成击键热力图,看看每天到底在“摸鱼”还是“搬砖”? 数据采集(监听)、持久化(I/O)与可视化展示,必须是三个完全独立的模块,这符合单一职责原则。在多线程读写 Python 字典时,锁住的时间要尽可能短,防止 I/O 线程把高频的监听线程阻塞住。这类涉及底层的代码与“键盘记录木马”只有一线之隔。永远不要把击键记录通过网络上传,所有数据必须localhost消化。人脑对枯燥的 JSON 日志是不敏感的,但对颜色和空间极其敏感。这也是为什么 Prometheus + Grafana 是标配。使用ctypes。 阅读详情

最新互联网大厂面试真题、Java程序员面试策略(面试前的准备、面试中的技巧)请访问GitHub


一. 前言

之前在 Collection移除元素操作 相关的文章中提到了 Collectors 。相信很多同学对这个比较感兴趣,那我们今天就来研究一下 Collectors 。

二. Collectors 的作用

Collectors 是 Java 8 加入的操作类,位于 java.util.stream 包下。它会根据不同的策略将元素收集归纳起来,比如最简单常用的是将元素装入Map、Set、List 等可变容器中。特别对于 Java 8 Stream Api 来说非常有用。它提供了collect() 方法来对 Stream 流进行终结操作派生出基于各种策略的结果集。我们就借助于 Stream 来熟悉一下 Collectors 吧。我们依然用昨天的例子:

List<String> servers = new ArrayList<>();
servers.add("Felordcn");
servers.add("Tomcat");
servers.add("Jetty");
servers.add("Undertow");
servers.add("Resin");

三. Java 8 中 Collectors 的方法

Collectors 提供了一系列的静态方法供我们使用,通常情况我们静态导入即可使用。接下来我们来看看都提供了哪些方法吧。

3.1 类型归纳

这是一个系列,作用是将元素分别归纳进可变容器 List、Map、Set、Collection 或者ConcurrentMap 。

Collectors.toList();
Collectors.toMap();
Collectors.toSet();
Collectors.toCollection();
Collectors.toConcurrentMap();

我们可以根据以上提供的 API 使用 Stream 的 collect 方法中的转换为熟悉的集合容器。非常简单这里不再演示。

3.2 joining

将元素以某种规则连接起来。该方法有三种重载 joining(CharSequence delimiter) 和 joining(CharSequence delimiter,CharSequence prefix,CharSequence suffix)

//   输出 FelordcnTomcatJettyUndertowResin
servers.stream().collect(Collectors.joining());
//   输出 Felordcn,Tomcat,Jetty,Undertow,Resin
servers.stream().collect(Collectors.joining("," ));
//   输出 [Felordcn,Tomcat,Jetty,Undertow,Resin]
servers.stream().collect(Collectors.joining(",", "[", "]"));

用的比较多的是读取 HttpServletRequest 中的 body :

HttpServletRequest.getReader().lines().collect(Collectors.joining());

3.3 collectingAndThen

该方法先执行了一个归纳操作,然后再对归纳的结果进行 Function 函数处理输出一个新的结果。

// 比如我们将servers joining 然后转成大写,结果为: FELORDCN,TOMCAT,JETTY,UNDERTOW,RESIN   
servers.stream.collect(Collectors.collectingAndThen(Collectors.joining(","), String::toUpperCase));

3.4 groupingBy

按照条件对元素进行分组,和 SQL 中的 group by 用法有异曲同工之妙,通常也建议使用 Java 进行分组处理以减轻数据库压力。groupingBy 也有三个重载方法
我们将 servers 按照长度进行分组:

// 按照字符串长度进行分组    符合条件的元素将组成一个 List 映射到以条件长度为key 的 Map<Integer, List<String>> 中
servers.stream.collect(Collectors.groupingBy(String::length))

如果我不想 Map 的 value 为 List 怎么办? 上面的实现实际上调用了下面的方式:

//Map<Integer, Set<String>>
servers.stream.collect(Collectors.groupingBy(String::length, Collectors.toSet()))

我要考虑同步安全问题怎么办? 当然使用线程安全的同步容器啊,那前两种都用不成了吧! 别急! 我们来推断一下,其实第二种等同于下面的写法:

Supplier<Map<Integer,Set<String>>> mapSupplier = HashMap::new;
Map<Integer,Set<String>> collect = servers.stream.collect(Collectors.groupingBy(String::length, mapSupplier, Collectors.toSet()));

这就非常好办了,我们提供一个同步 Map 不就行了,于是问题解决了:

Supplier<Map<Integer, Set<String>>> mapSupplier = () -> Collections.synchronizedMap(new HashMap<>());
Map<Integer, Set<String>> collect = servers.stream.collect(Collectors.groupingBy(String::length, mapSupplier, Collectors.toSet()));

其实同步安全问题 Collectors 的另一个方法 groupingByConcurrent 给我们提供了解决方案。用法和 groupingBy 差不多。

3.5 partitioningBy

partitioningBy 我们在本文开头的提到的文章中已经见识过了,可以看作 groupingBy 的一个特例,基于断言(Predicate)策略分组。这里不再举例说明。

3.6 counting

该方法归纳元素的的数量,非常简单,不再举例说明。

3.7 maxBy/minBy

这两个方法分别提供了查找大小元素的操作,它们基于比较器接口 Comparator 来比较 ,返回的是一个 Optional 对象。 我们来获取 servers 中最小长度的元素:

// Jetty  
Optional<String> min = servers.stream.collect(Collectors.minBy(Comparator.comparingint(String::length)));

这里其实 Resin 长度也是最小,这里遵循了 “先入为主” 的原则 。当然 Stream.min() 可以很方便的获取最小长度的元素。maxBy 同样的道理。

3.8 summingInt/Double/Long

用来做累加计算。计算元素某个属性的总和,类似 Mysql 的 sum 函数,比如计算各个项目的盈利总和、计算本月的全部工资总和等等。我们这里就计算一下 servers 中字符串的长度之和 (为了举例不考虑其它写法)。

// 总长度 32 
servers.stream.collect(Collectors.summingint(s -> s.length()));

3.9 summarizingInt/Double/Long

如果我们对 3.6章节-3.8章节 的操作结果都要怎么办?难不成我们搞5个 Stream 流吗? 所以就有了 summarizingInt、summarizingDouble、summarizingLong 三个方法。
这三个方法通过对元素某个属性的提取,会返回对元素该属性的统计数据对象,分别对应 IntSummaryStatistics、DoubleSummaryStatistics、LongSummaryStatistics。我们对 servers 中元素的长度进行统计:

DoubleSummaryStatistics doubleSummaryStatistics = servers.stream.collect(Collectors.summarizingdouble(String::length));
// {count=5, sum=32.000000, min=5.000000, average=6.400000, max=8.000000}
System.out.println("doubleSummaryStatistics.toString() = " + doubleSummaryStatistics.toString());

结果 DoubleSummaryStatistics 中包含了 总数,总和,最小值,最大值,平均值 五个指标。

3.10 mapping

该方法是先对元素使用 Function 进行再加工操作,然后用另一个Collector 归纳。比如我们先去掉 servers 中元素的首字母,然后将它们装入 List 。

// [elordcn, omcat, etty, ndertow, esin]
servers.stream.collect(Collectors.mapping(s -> s.substring(1), Collectors.toList()));

有点类似 Stream 先进行了 map 操作再进行 collect :

servers.stream.map(s -> s.substring(1)).collect(Collectors.toList());

3.11 reducing

这个方法非常有用!但是如果要了解这个就必须了解其参数 BinaryOperator 。 这是一个函数式接口,是给两个相同类型的量,返回一个跟这两个量相同类型的一个结果,伪表达式为 (T,T) -> T。默认给了两个实现 maxBy 和 minBy ,根据比较器来比较大小并分别返回最大值或者最小值。当然你可以灵活定制。然后 reducing 就很好理解了,元素两两之间进行比较根据策略淘汰一个,随着轮次的进行元素个数就是 reduce 的。那这个有什么用处呢? Java 官方给了一个例子:统计每个城市个子最高的人。

Comparator<Person> byHeight = Comparator.comparing(Person::getHeight);
Map<String, Optional<Person>> tallestByCity = people.stream()
                          .collect(Collectors.groupingBy(Person::getCity, Collectors.reducing(BinaryOperator.maxBy(byHeight))));

结合最开始给的例子你可以使用 reducing 找出最长的字符串试试。

上面这一层是根据 Height 属性找最高的 Person ,而且如果这个属性没有初始化值或者没有数据,很有可能拿不到结果所以给出的是 Optional。 如果我们给出了 identity 作一个基准值,那么我们首先会跟这个基准值进行 BinaryOperator 操作。
比如我们给出高于 2 米 的人作为 identity。 我们就可以统计每个城市不低于 2 米 而且最高的那个人,当然如果该城市没有人高于 2 米则返回基准值identity :

Comparator<Person> byHeight = Comparator.comparing(Person::getHeight);
Person identity= new Person();
           identity.setHeight(2.);
           identity.setName("identity");
     Map<String, Person> collect = persons.stream()
                        .collect(Collectors.groupingBy(Person::getCity, Collectors.reducing(identity, BinaryOperator.maxBy(byHeight))));

这时候就确定一定会返回一个 Person 了,最起码会是基准值identity 不再是 Optional 。

还有些情况,我们想在 reducing 的时候把 Person 的身高先四舍五入一下。这就需要我们做一个映射处理。定义一个 Function<? super T, ? extends U> mapper 来干这个活。那么上面的逻辑就可以变更为:

   Comparator<Person> byHeight = Comparator.comparing(Person::getHeight);
        Person identity = new Person();
        identity.setHeight(2.);
        identity.setName("identity");
        // 定义映射 处理 四舍五入
        Function<Person, Person> mapper = ps -> {
            Double height = ps.getHeight();

            BigDecimal decimal = new BigDecimal(height);
            Double d = decimal.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
            ps.setHeight(d);
            return ps;
        };
        Map<String, Person> collect = persons.stream()
                .collect(Collectors.groupingBy(Person::getCity, Collectors.reducing(identity, mapper, BinaryOperator.maxBy(byHeight))));

四. 总结

今天我们对 Java 8 中的 Collectors 进行了详细的讲解。如果你熟悉了 Collectors 操作 Stream 会更加得心应手。

【Claude】Not logged in · Please run /login 报错已解决 意味着 Claude Code 没有找到任何有效凭证。直接/login——交互式首选;检查——排查环境变量污染;CI 用——自动化场景标准方案;macOS Keychain 异常——/logout/login重置;时钟偏差——校准系统时间。参考:Claude Code 官方《错误参考》"身份验证"章节、官方认证优先级文档、社区 Token 过期排查记录。 阅读详情

相关推荐

DNS入侵检测 datacon2020

DNS入侵检测 datacon2020。

weixin_51491521的博客 523

Java Stream 最全操作用法合集

Java 8 引入了Stream流的操作,让我们在开发的过程中感受到了很多的便利,小宋我也花时间总结了下关于Stream的堪称最全的使用方法,话不多说,直接放大招。

u012062957的博客 6562

HIL(硬件在环)技术汇总梳理

HIL(Hardware-in-the-Loop)测试领域的知名公司有dSPACE、NI、Vector和speedgoat等,本文是针对这几家HIL技术的对比分析。

Mr.Cssust的博客 3687

Stream 流常见基本操作

Stream 流是 Java8 新特性之一,我们在实际开发中借助 Stream 流搭配 Lambda 表达式,可以很方便的完成一些对集合的操作,可以显著的提升开发的效率和性能。

LEE180501的博客 2656

deepin搭建samba服务器

一.为什么要用Samba? Samba的主要任务就是实现Linux系统和Windows系统之间的资源共享。二.需要的软件? 我是在deepin上实现的,在终端中使用一下两句命令,就可以安装Samba的软件包 $sudo apt-get install samba //安装samba 三.Samba服务的组成 Samba的核心是两个守护进程smbd和nmbd。当然,它

xbrother123的博客 8598

零、HarmonyOS应用开发者基础学习总览

零、HarmonyOS应用开发者基础学习总览

weixin_45029825的博客 1454

Java Stream常见用法汇总,开发效率大幅提升

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来对 Java 集合运算和表达的高阶抽象。Stream API 可以极大提高 Java 程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

Tyson0314的博客 1323

STM32Cube高效开发教程<高级篇><FreeRTOS>(一)-----FreeRTOS基础

一、 FreeRTOS概述声明:本人水平有限,博客可能存在部分错误的地方,请广大读者谅解并向本人反馈错误。本专栏博客参考《STM32Cube高效开发教程(高级篇)》,有意向的读者可以购买正版书籍辅助学习,本书籍由王维波老师、鄢志丹老师、王钊老师倾力打造,书籍内容干货满满。写在前面:今天就算正式开始高级篇的博客编写了,我本人也是第一次学习FreeRTOS,所以整体的进度会比较慢,博客更新可能不太会及时,希望大家原谅。一、 FreeRTOS概述。

我的博客 1848

【java基础】吐血总结Stream流操作

java 8 是一个非常成功的版本,这个版本新增的Stream,配合同版本出现的Lambda,给我们操作集合(Collection)提供了极大的便利。那么什么是Stream?Stream将要处理的元素集合看作一种流,在流的过程中,借助Stream API对流中的元素进行操作,比如:筛选、排序、聚合等。Stream中间操作,每次返回一个新的流,可以有多个。(筛选filter、映射map、排序sorted、去重组合skip—limit)终端操作,每个流只能进行一次终端操作,终端操作结束后流无法再次使用。

weixin_45131680的博客 1521

Cadence OrCAD Capture原理图中为功能模块分配ROOM的方法

本文详解介绍原理图设计阶段为原理图模块分配ROOM的方法。

fydar的博客 1346

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

学完这篇掌握流(stream),大大提高你的编程效率!

在 Java 中,流(Stream) 是 Java 8 引入的一套处理集合(Collection)的高级 API,它专注于对数据进行高效的聚合操作(如筛选、排序、映射、统计等),同时支持函数式编程和链式操作,让代码更简洁、易读。使用流通常分为 3 个步骤:常见操作:从 List 创建流: 或 (并行流)流收集为 List:示例:筛选 + 排序 + 转 List ②流与 Set Set 用于处理去重场景,流操作与 Set 结合可高效去重和转换。常见操作:从 Set 创建流:流收集为 Set:(自动

jiajiachonga的博客 2558

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

51c大模型~合集110

为了解决这一问题,在稠密化过程中,我们对容易引起退化和梯度集中的具有极端延展率的高斯面片进行了筛选,并对其增殖过程进行了限制,从而在不牺牲性能的情况下有效稳定了训练过程,保障了优化过程的顺利进行。大规模场景的重建往往还意味着显著的训练开销,要重建 1.97 平方千米的区域会产生接近两千万的高斯点,这意味着 4.6G 的存储以及 31.5G 的显存开销,以及超过三小时的训练时长。站在 AI 研究者的角度,得到了《苦涩的教训》,意味着在总结教训的过程中明确了什么是「更好」的。第二类则瞄准了相对复杂的问题。

whaosoft~aiotの开发板商城 2603

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Stream流保姆级详解,快来看吧!!

Stream 流是 Java 8 中引入的一个重要新特性,它允许我们以声明式的方式处理集合数据。Stream 流就像是一个流水线,我们可以在这个流水线上对数据进行一系列的操作,比如过滤、映射、排序等,最终得到我们想要的结果。与传统的集合遍历方式相比,Stream 流具有代码简洁、可读性高、易于并行处理等优点。它不会改变原始集合的数据,所有的操作都是在流上进行的,并且只有在执行终止操作时,中间操作才会真正执行,这就是所谓的 “惰性求值”。

2402_89658129的博客 2525

Stream流技巧总结

我们可以将一个自定义的。

沉梦听雨的博客 1938

Stream流使用方法总结

Java8中Stream详细用法大全

qq_44974032的博客 304

Java 8 中的 Streams API 详解

陈争云, 占宇剑, 司磊 发布: 2014-09-11 原创地址:https://developer.ibm.com/zh/articles/j-lo-java8streamapi/ 为什么需要 Stream Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream。Java 8 中的

qq_34327621的博客 648

Stream流的常用方法大全

Stream流常用方法

weixin_52317961的博客 3万+

Java8 中Stream的常用技巧

Java8中,Stream数据流操作对集合操作做了极大的简化,学习了Stream,以后我们可以不用for循环就能对集合进行很多操作。 文章目录Stream的初始化流操作1、遍历操作(map)2、过滤操作(filter)3、循环操作(forEach)4、返回特定结果集合(limit/skip)5、排序(sort/min/max/distinct)6、匹配(Match相关) Stream的初始化 Java中所有的Stream操作,都是针对流对象的,故使用Stream必须得初始化得到Stream类型对象: S

龙套的博客 970

Java 8 Stream 的终极技巧——Collectors 操作

1. 前言 昨天在 Collection 移除元素操作[1] 相关的文章中提到了 Collectors 。相信很多同学对这个比较感兴趣,那我们今天就来研究一下 Collectors 。 2. Collectors 的作用 Collectors 是 Java 8 加入的操作类,位于 java.util.stream 包下。它会根据不同的策略将元素收集归纳起来,比如最简单常用的是将元素装入...

码农小胖哥 2653

Java8中Stream的使用技巧

来源:https://www.jianshu.com/p/9fe8632d0bc2 简介: 1.stream是对集合对象功能的增强,用于对集合对象的各种操作,或者大批量数据操作 2.stream会根据要求,隐式的进行内部便利,然后做出相应的数据转换 优点: 函数式编程使得代码更好的表达业务逻辑的意图,代码易读性高,也更易于维护 相关操作: Filter 1.遍历数据并检查元素...

spWarrior的博客 402

Stream使用技巧(1)------数据处理技巧

Stream使用技巧(1)------数据处理技巧 一. 背景 作为java8新特性之一的Stream API为开发者带来了极大的便利,它可以对我们需要操作的集合进行非常复杂的操作,以活的我们想要的结果. 本文不会告诉你什么是Stream,毕竟网上花里胡哨的使用教程已经让我应接不暇,本系列博文只是记录一些Stream的使用技巧,便于方便的查找和参考. 本博文会无限更新,有新的使用方法会逐渐添加进来,如果有小伙伴有新奇的使用技巧,也可以发出来一起分享. 本文中默认使用的对象user如下: @Data

剑小纯的夜话白鹭 650

jdk8 Stream流的使用及其技巧

1、创建Stream的方法 1.1、通过 java.util.Collection.stream() 方法用集合创建流(推荐使用) List<String> list = Arrays.asList("1","2","3"); Stream<String> stream = list.stream(); 1.2、使用java.util.Arrays.stream(T[] array)方法用数组创建流 String [] arr={"1","2","3","4"}; Stream&l

小爽帅到拖网速的博客 683

sstream的一些技巧

Steps for using Stringstream: Include the Stringstream library. #include Use getline to get the string from the user std::getline(std::cin, stringVariable); Convert the string variable to a f

u011535421的博客 399

Java8之新特性Stream流简单实用小技巧

Java8新增特性之Stream流 文章目录前言1、小技巧1.1 数组转集合1.2 统计数组元素中的个数1.3 基本数据类型的数组自定义排序1.4 统计数组中前 k 个个高频元素总结 前言 虽然 stream在 Java8 中就已经被引入,但是大多数人却没有去使用这个十分有用的特性,本文就通过介绍几个通过使用stream让代码更简洁、可读,来让你了解stream的方便之处。 1、小技巧 1.1 数组转集合 相信经常刷LeetCode的小伙伴,偶尔会遇到需要将List与基本类型数组进行互转的情况,然后就.

qq_43591363的博客 511

istream用法大全

做校招题时cin/cout总是用不好,所以很有必要总结一下i/o的用法,完全掌握其用法才会得心应手! kai1、streamsize gcount( ) const // 返回最后一次cin输出的字符个数,包括字符串结束符'\0';// cin.gcount example #include &lt;iostream&gt; // std::cin, std::cout int main...

weixin_37562427的博客 1万+

Kafka Stream 以及其他流处理框架对比

1. Kafka Stream Introduction 假设我们需要对kafka 消息做流数据分析,例如: 对部分消息做过滤 每分钟计算一次收到了多少消息 这种情况下,对于消息过滤以及定时统计,甚至是进行流的合并,是几个基本的流式处理。但是在这种情况下,仅使用Kafka Producer 与 Consumer 很难实现这些功能,因为它们属于非常底层的API,并且并不是d...

weixin_30872337的博客 747
上一篇: 不用怀疑!这就是把Java.I/O流讲解的最清楚的一篇文章
下一篇: 美团 MySQL 数据库巡检系统的设计与应用
Java_Cappuccino
博客等级 码龄7年 17粉丝 64原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值