深入了解Java 8 新特性:Stream流的实践应用(二)

阅读建议

嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议:

  1. 本篇文章大概8000多字,预计阅读时间长需要10分钟(不要害怕字数过多,其中有一大部分是示例代码,读起来是比较轻松的)。
  2. 本篇文章兼具实战性和理论性,是一篇质量分数较高的技术干货文章,建议收藏起来,方便时常学习与回顾,温故而知新。
  3. 创作不易,免费的点赞、关注,请走上一走,算是对博主一些鼓励,让我更有动力输出更多的干货内容。

Collectors类的核心方法

        Stream是一个数据结构,它提供了一种方便的方式来处理和操作数据,Stream.collect() 方法则用于将 Stream 中的元素收集到指定的收集器(Collector)中,返回一个结果对象。收集器(Collector)可以是任何实现了 Collector 接口的对象,用于定义如何将 Stream 中的元素收集到结果对象中。而Collectors可以看作是收集器(Collector)的生产工厂,可以调用具体的静态方法返回一个具体的收集器。常用的如下:

Collectors#toCollection

        Collectors类的toCollection()方法用于将Stream中的元素收集到新的集合中。这个方法的功能作用是接收一个输入流并产生一个输出结果,即把Stream中的元素收集到某种类型的集合中,这里的某类类型集合可由用户以lambda表达式来定义,如:

  1. 收集元素到ArrayList:通过调用toCollection()方法和传递ArrayList类型的构造方法,可以将Stream中的元素收集到ArrayList中。
  2. 收集元素到HashSet:通过调用toCollection()方法和传递HashSet类型的构造方法,可以将Stream中的元素收集到HashSet中。
  3. 收集元素到LinkedHashSet:通过调用toCollection()方法和传递LinkedHashSet类型的构造方法,可以将Stream中的元素收集到LinkedHashSet中。
  4. 收集元素到TreeSet:通过调用toCollection()方法和传递TreeSet类型的构造方法,可以将Stream中的元素收集到TreeSet中。
  5. 收集元素到List或Set:通过调用toCollection()方法和传递适当的集合类型构造方法,可以将Stream中的元素收集到List或Set中。

示例

@Test
public void test22(){Stream<String> stream = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu");HashSet<String> set = stream.collect(Collectors.toCollection(() -> new HashSet<String>()));System.out.println(set.toString());
}

Collectors#toList

        Collectors.toList() 用于将 Stream 中的元素收集到一个新的 List 中。这个方法返回一个 Collector 对象,该对象定义了如何将 Stream 中的元素收集到 List 中。

Collectors#toUnmodifiableList

        Collectors.toUnmodifiableList() 用于将 Stream 中的元素收集到一个新的不可修改的 List 中。这个方法返回一个 Collector 对象,该对象定义了如何将 Stream 中的元素收集到一个不可修改的 List 中。与Collectors#toList区别就是返回的 List 是不可修改的,无法被重新赋值或添加/删除元素。

Collectors#toSet

        Collectors.toSet() 用于将 Stream 中的元素收集到一个新的 Set 中。这个方法返回一个 Collector 对象,该对象定义了如何将 Stream 中的元素收集到 Set 中。

        需要注意的是,Collectors.toSet() 方法返回的 Collector 对象可以处理任意类型的 Stream,包括泛型 Stream。这意味着您可以使用该方法将任何类型的元素收集到 Set 中。另外,由于 Set 本身不允许存在重复的元素,因此 Collectors.toSet() 方法会自动去重,只保留唯一的元素。

Collectors#toUnmodifiableSet

        Collectors.toUnmodifiableSet()用于将 Stream 中的元素收集到一个新的、不可修改的 Set 中。这个方法返回一个 Collector 对象,该对象定义了如何将 Stream 中的元素收集到一个不可修改的 Set 中。

        需要注意的是,由于返回的 Set 是不可修改的,因此不能添加或删除元素。这可以确保收集到的元素不会在后续操作中被修改。此外,与 Collectors.toList() 方法类似,toUnmodifiableSet() 方法也可以处理任意类型的 Stream,包括泛型 Stream。

Collectors#joining

        Collectors.joining() 方法用于连接多个元素。该方法返回一个 Collector 实例,方便在流收集器上进行链式操作。Collectors.joining() 方法以遭遇元素的顺序拼接元素。我们可以传递自定义的拼接字符串、前缀和后缀。

@Test
public void test23() {Stream<String> stream = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu");String string = stream.collect(Collectors.joining("-"));System.out.println(string);//输出结果:zhangsan-lisi-wangwu-zhaoliu
}

Collectors#counting

        Collectors.counting()用于计算Stream中元素的数量。它会遍历输入的Stream,对每个元素进行计数,并返回一个Long类型的值,表示元素的数量。

@Test
public void test24() {Stream<String> stream = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu");;Long count = stream.filter(item->item.startsWith("a")).collect(Collectors.counting());System.out.println(count);
}

Collectors#minBy

        Collectors.minBy()用于在Stream中的元素上执行最小值计算操作。该方法方法接受一个比较器作为参数,并将该比较器用于Stream中的元素。它会计算每个元素的最小值,并返回一个包含最小值元素的Optional对,Optional对象包装了最小值元素。如果Stream为空,则返回的Optional对象为空(empty)。

@Test
public void test25() {Stream<Integer> stream = Stream.of(1, 6, 29, 45, 2);Integer min = stream.collect(Collectors.minBy((v1, v2) -> {if (v1 > v2) {return 1;} else if (v1 < v2) {return -1;} else {return 0;}})).get();System.out.println(min);//输出结果为1
}

Collectors#maxBy

        Collectors.maxBy()用于将Stream中的元素进行比较并找出最大值。该方法接受一个比较函数作为参数,该比较函数定义了如何比较Stream中的元素。这个比较函数可以是自定义的,例如比较两个字符串的长度、比较两个日期的日期值等,通过比较操作可以找出Stream中最大的元素。

@Test
public void test26() {Stream<Integer> stream = Stream.of(1, 6, 29, 45, 2);Integer min = stream.collect(Collectors.minBy((v1, v2) -> {if (v1 > v2) {return -1;} else if (v1 < v2) {return 1;} else {return 0;}})).get();System.out.println(min);//输出结果为45
}

Collectors#summingInt

        Collectors.summingInt()用于将Stream中的元素进行求和操作。该方法的功能作用是接受一个将对象映射为int的函数,并返回一个收集器,用于计算元素的和。在传递给普通的collect方法后,该收集器即执行所需的汇总操作,计算元素的和。

@Test
public void test26() {Stream<Integer> stream = Stream.of(10, 20, 30, 40, 50);Integer sum = stream.collect(Collectors.summingInt(item -> item));System.out.println(sum);//输出结果为150
}

Collectors#averagingInt

        Collectors.averagingInt()方法的功能作用是计算数值的平均数。它接受一个将对象映射为求和所需的int的函数,并返回一个收集器。在传递给普通的collect方法后,该收集器即执行所需的汇总操作,计算元素的平均值。

@Test
public void test27() {Stream<Integer> stream = Stream.of(2, 4, 6);double sum = stream.collect(Collectors.averagingInt(item->item));System.out.println(sum);//输出结果为4.0
}

Collectors#reducing

        Collectors.reducing()方法的功能作用是对Stream中的元素进行归约操作,将Stream中的元素聚合为单一的值。该方法接受一个BinaryOperator作为参数,用于指定如何将两个元素进行归约操作。

@Test
public void test28() {Stream<Integer> stream = Stream.of(2, 4, 6);Integer sum = stream.collect(Collectors.reducing(Integer::sum)).get();System.out.println(sum);Stream<Integer> stream2 = Stream.of(1, 2, 3);Optional<Integer> optional = stream2.collect(Collectors.reducing((v1, v2) -> v1 + v2));Integer sum2 = optional.get();System.out.println(sum2);
}

Collectors#groupingBy

        Collectors.groupingBy()用于将Stream中的元素进行分组操作。具体来说,先通过传递一个分类函数作为参数,Collectors.groupingBy()方法可以将Stream中的元素按照该函数的返回值进行分组。这个分类函数接受一个元素作为输入,并返回一个用于分组的键。然后Collectors.groupingBy()方法返回一个Collector对象,该对象定义了如何将分组后的结果收集到一个Map中。默认情况下,它会收集每个分组的元素并返回一个Map,其中键是分类函数的返回值,值是对应的元素列表。

@Test
public void test29(){List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19));Map<String, List<Student>> map = list.stream().collect(Collectors.groupingBy(item -> item.getName()));System.out.println(map.toString());
}

Collectors#groupingByConcurrent

        Collectors#groupingByConcurrent方法与Collectors#groupingBy方法功能类似,唯一有些区别就是,Collectors#groupingByConcurrent方法返回值是ConcurrentMap

@Test
public void test30(){List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19));ConcurrentMap<String, List<Student>> concurrentMap = list.stream().collect(Collectors.groupingByConcurrent(item -> item.getName()));System.out.println(concurrentMap.toString());
}

Collectors#partitioningBy

        Collectors.partitioningBy()用于将Stream中的元素进行分区操作。该方法的功能作用是根据给定的二元函数将Stream中的元素分成两个部分,并返回一个包含两个子列表的Map。

示例

根据姓名是否以z开头对姓名集合进行分区

@Test
public void test31(){Stream<String> stream = Stream.of("zhangsan", "lisi", "wangwu", "zhaoliu");Map<Boolean, List<String>> map = stream.collect(Collectors.partitioningBy(item -> item.startsWith("z")));System.out.println(map.toString());//输出结果:{false=[lisi, wangwu], true=[zhangsan, zhaoliu]}
}

Collectors#toMap

        Collectors.toMap()用于将Stream中的元素收集到Map中,它接受两个函数作为参数,一个用于映射键,另一个用于映射值。这些函数将应用于Stream中的每个元素,以生成对应的键和值。在收集元素时,如果存在重复的键,Collectors.toMap()方法的行为取决于是否提供了合并函数。如果提供了合并函数,该函数将用于处理重复键,以决定如何合并这些键的值。如果没有提供合并函数,那么在遇到重复键时,则会抛出IllegalStateException异常。

        示例

        把学生信息的List集合,转化为一个Map,key:学生姓名,value:学生年龄

@Test
public void test32(){List<Student> list = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19));Map<String, Integer> map = list.stream().collect(Collectors.toMap(item -> item.getName(), item -> item.getAge()));System.out.println(map.toString());//输出结果:{lisi=19, zhangsan=18}List<Student> list2 = Arrays.asList(new Student("zhangsan", 18), new Student("lisi", 19),new Student("lisi", 20));Map<String, Integer> map2 = list2.stream().collect(Collectors.toMap(item -> item.getName(), item -> item.getAge(), (v1, v2) -> {return v2;//如果key发生重复,则取重复对象的最后一个对象的val}));System.out.println(map2);
}

Collectors#toUnmodifiableMap

        Collectors.toUnmodifiableMap()用于将Stream中的元素收集到一个不可修改的Map中。它接受一个二元函数作为参数,用于将Stream中的元素映射为Map中的键值对。返回的Map是不可修改的,即无法添加、删除或修改其中的元素。这样可以保证Map的安全性,防止意外修改原始数据。除了这些特性,在用法上与Collectors#toMap相同

Stream使用过程特别需要注意的几个坑

        在使用Java的Stream流时,有一些容易踩坑的地方需要注意:

  1. 空指针异常:在使用Stream时,需要注意避免空指针异常。例如,在使用filter方法过滤列表时,如果列表为空,会导致空指针异常。因此,在使用Stream之前,需要先判断数据是否为空,避免出现异常。
  2. 内存溢出:在使用Stream进行大数据处理时,需要注意内存溢出的问题。如果数据量太大,而内存不足,会导致内存溢出。因此,需要根据数据量和机器的内存情况合理选择数据分块大小和处理方式,避免出现内存溢出的问题。
  3. 并行流的正确使用:在使用并行流时,需要注意线程安全的问题。如果多个线程同时修改同一个数据,可能会导致数据不一致的问题。因此,在使用并行流时,需要确保数据不会被多个线程同时修改。
  4. 终止操作:在使用Stream时,需要注意终止操作。如果没有正确地终止Stream,可能会导致数据丢失或者出现其他异常。因此,在使用Stream时,需要确保每个操作都正确地终止。
  5. 链式操作的可读性:在使用链式操作时,需要注意可读性问题。如果链式操作太长或者操作太多,会导致代码难以理解和维护。因此,在使用链式操作时,需要合理控制操作的长度和数量,提高代码的可读性和可维护性。
  6. 类型转换问题:在使用Stream的map方法进行类型转换时,需要注意类型转换的正确性。例如,将一个字符串列表映射为对应的整数列表时,如果转换出错会导致类型转换异常。因此,在进行类型转换时,需要确保转换的正确性。
  7. 延迟加载问题:Stream的延迟加载问题是指在Stream操作完成之后,结果不会立即计算并返回,而是需要在使用结果时才会进行计算。这种延迟加载的特性可以减少内存占用和提高性能,但也可能导致一些问题。因此,在使用Stream时需要注意,需要通过正确地终止操作、缓存结果、使用并行流和使用正确的操作等方法来解决该问题。

Stream 的应用场景

        Java Stream的应用场景非常广泛,如果在实际的业务中以下类似的技术需求,那么都是可以使用Stream的相关能力助力业务实现:

  1. 数据筛选与过滤:Stream提供了filter方法,可以根据指定的条件筛选出符合要求的元素。在处理大量数据时,使用Stream可以避免手动编写循环和if语句的繁琐工作,使代码更加简洁易读。
  2. 映射操作:Stream的map方法可以将元素映射为其他对象。例如,可以将一个字符串列表映射为对应的字符串长度列表。
  3. 排序操作:Stream的sorted方法可以对元素进行排序。例如,可以将一个整数列表按照升序或降序排列。
  4. 聚合操作:Stream的reduce方法可以将元素进行聚合操作,例如将一个整数列表累加成一个整数。
  5. 收集操作:Stream的collect方法可以将元素收集到一个集合中。例如,可以将一个字符串列表收集到一个List中。
  6. 遍历操作:Stream的forEach方法可以遍历元素并执行指定的操作。例如,可以遍历一个整数列表并输出每个整数的值。

总结

        总之,Java Stream可以应用于各种数据处理的场景,包括但不限于数据筛选与过滤、映射操作、排序操作、聚合操作、收集操作和遍历操作等。使用Stream可以简化代码、提高可读性和可维护性,并提高系统的性能和效率。

下一篇:深入了解Java 8 新特性:Stream流的实践应用(一) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/155272.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RAAGR2-Net:一种使用多个空间帧的并行处理的脑肿瘤分割网络

RAAGR2-Net: A brain tumor segmentation network using parallel processing of multiple spatial frames RAAGR2-Net&#xff1a;一种使用多个空间帧的并行处理的脑肿瘤分割网络背景贡献实验N4 bias-field-correction 数据预处理Z-score and re-sampling Z-score归一化&#…

redis高可用---持久化

redis高可用 在集群当中有一个非常重要的指标&#xff0c;提供正常服务的时间的百分比(365天) 99.9%&#xff0c;redis高可用含义更广泛&#xff0c;支持服务是指标之一&#xff0c;数据容量扩展&#xff0c;数局的安全性。&#xff08;容量、安全性&#xff09; redis中实现高…

数据仓库模式之详解 Inmon 和 Kimball

目录 一、前言 二、企业信息工厂&#xff08;Inmon&#xff09; 2.1 概念 2.2 主要组件 2.3 流程 三、多维数据仓库&#xff08;Kimball&#xff09; 3.1 概念 3.2 核心组件 3.3 流程 四、异同及用途对比 4.1 异同对比 4.2 特征比较 一、前言 大部分关于数据仓库构建…

小微初创企业,如何利用媒体宣传快速成长

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 对于小微初创企业来说&#xff0c;利用媒体宣传可以快速提升品牌知名度、扩大影响力&#xff0c;进而促进企业的成长。 1.确定宣传目标&#xff1a;是增加销售、提升品牌知名度、还是推…

JVM对象创建与内存分配

对象的创建 对象创建的主要流程&#xff1a; 类加载推荐博客&#xff1a;JVM类加载机制详解 类加载检查 虚拟机遇到一条new指令时&#xff0c;首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用&#xff0c;并且检查这个符号引用代表的类是否已被加载、解析…

Failed to load resource: net::ERR_UPLOAD_FILE_CHANGED 谷歌浏览器就会有这个问题 其他的浏览器没有

Failed to load resource: net::ERR_UPLOAD_FILE_CHANGED 10 10: Difficulties in file uploading through all browsers and applications

mac添加Chrome插件的方法

如果是.crx的插件 更改后缀crx为zip 后续步骤同下文.zip文件 如果是.zip的插件 使用终端进行解压 注意不要用解压工具解压&#xff0c;一定要用终端&#xff0c;命令行解压 // 进入到“插件名.zip”文件的目录下&#xff0c;输入下面命令&#xff1a; unzip 插件名.zip -…

「ResNet-18」70 个犬种的图片分类

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&…

LeetCode【45】跳跃游戏2

题目&#xff1a; 思路&#xff1a; 注意和跳跃游戏【55】不同的是&#xff0c;题目保证可以跳到nums[n-1];那么每次跳到最大即可 代码&#xff1a; public class LeetCode45 {public static int jump(int[] nums) {int jumps 0;int currentEnd 0;int farthest 0;for(int…

Android Serializable / Parcelable

Serializable 序列化,将对象转为二进制序列 Parcelable 不是序列化,属于进程间通信,不需要IO/操作,没有拷贝内存的操作, Object -> ShareMemory -> Object 不需要IO,使用内存共享等方式 Kotlin inline fun 内联函数 TCP协议将数据包拆分,进行发送,保证网络数据的可…

基于纹理特征的kmeas聚类的图像分割方案

Gabor滤波器简介 在图像处理中&#xff0c;以Dennis Gabor命名的Gabor滤波器是一种用于纹理分析的线性滤波器&#xff0c;本质上是指在分析点或分析区域周围的局部区域内&#xff0c;分析图像中是否存在特定方向的特定频率内容。Gabor滤波器的频率和方向表示被许多当代视觉科学…

二十一、数组(3)

本章概要 Arrays的setAll方法增量生成 Arrays的setAll方法 在Java 8中&#xff0c; 在RaggedArray.java 中引入并在 ArrayOfGenerics.java.Array.setAll() 中重用。它使用一个生成器并生成不同的值&#xff0c;可以选择基于数组的索引元素&#xff08;通过访问当前索引&…

Android项目更新依赖和打包步骤和问题汇总

目录 1、Android 项目打包&#xff0c;32位包升级到64位包问题一&#xff1a;ERROR: Conflicting configuration : armeabi-v7a,x86-64,arm64-v8a,x86 in ndk abiFilters cannot be present when splits abi filters are set : x86,armeabi-v7a,arm64-v8a 2、Android项目依赖升…

pytest-base-url插件之配置可选的项目系统URL

前言 ①当我们的自动化代码完成之后&#xff0c;通常期望可以在不同的环境进行测试&#xff0c;此时可以将项目系统的URL单独拿出来&#xff0c;并且可以通过pytest.ini配置文件和支持pytest命令行方式执行。 ② pytest-base-url 是一个简单的pytest插件&#xff0c;它通过命…

【数据结构】HashMap 和 HashSet

目录 1.哈希表概念 2冲突 2.1概念 2.2 冲突-避免 2.3冲突-避免-哈希函数设计 2.4 冲突-避免-负载因子调节 ​编辑 2.5 冲突-解决-开散列/哈希桶 2.5冲突严重时的解决办法 3.实现 4.性能分析 5.与Java集合类的关系 1.哈希表概念 在顺序结构中&#xff0c;元素关键码和存…

【vue+eltable】修改表格滚动条样式

<style lang"scss" scoped> ::v-deep .el-table__body-wrapper::-webkit-scrollbar {width: 10px; /*纵向滚动条的宽度*/height: 10px; /*横向滚动条的高度*/ } /*定义滚动条轨道 内阴影圆角*/ ::v-deep .el-table__body-wrapper::-webkit-scrollbar-track {bo…

Java 多线程之 volatile(可见性/重排序)

文章目录 一、概述二、使用方法三、测试程序3.1 验证可见性的示例3.2 验证指令重排序的示例 一、概述 在Java中&#xff0c;volatile 关键字用于修饰变量&#xff0c;其作用是确保多个线程之间对该变量的可见性和禁止指令重排序优化。 当一个变量被声明为volatile时&#xff0…

高德地图点击搜索触发输入提示

减少调用次数&#xff0c;不用每输入一次调用一次&#xff0c;输入完后再触发搜索 效果图&#xff1a; ![Alt](https://img-home.csdnimg.cn/images/20220524100510.png dom结构 <div class"seach"><van-searchshow-actionv-model"addressVal"…

【使用vscode在线web搭建开发环境--code-server搭建】

官方版本下载 https://github.com/coder/code-server/releases?q4.0.0&expandedtrue使用大于版本3.8.0,因为旧版本有插件市场不能访问的情况版本太高需要更新环境依赖 拉取安装包 []# wget "https://github.com/coder/code-server/releases/download/v4.0.0/code-…

探访九牧绿色黑灯工厂,找寻“科技卫浴 世界九牧”的答案

文 | 螳螂观察 作者 | 余一 你所想象中的工厂是怎么样的&#xff1f;灯火通明、人声鼎沸、人来人往&#xff1f;如果告诉你一座工厂既没有灯&#xff0c;也没有人&#xff0c;但却还在持续生产&#xff0c;你会不会觉得这是不可思议的事&#xff1f; 如果不是亲眼见证&#…