Java函数式编程【二】【Stream的装饰】【中间操作】【map映射器】【摊平映射器flatMap】

一、Java的Stream流式编程中的中间操作
Java的Stream流式编程中,中间操作是对数据流进行处理的一种方式,这些操作通常返回流对象本身,以便可以链接更多的操作。以下是一些常见的中间操作:

  • filter(Predicate predicate) - 用于通过设定的条件过滤出元素。

  • sorted() - 对元素进行排序。

  • distinct() - 去除重复的元素。

  • limit(long maxSize) - 获取指定数量的流元素。

  • skip(long n) - 跳过操作,跳过某些元素。

  • peek() - 查看操作。允许你在不影响流的主要处理逻辑的情况下,查看或使用流中的每个元素。这个方法可以用来进行一些调试或日志记录等操作。下面是一个示例:

peek例程

List<String> fruits = Arrays.asList("apple", "banana", "orange", "grape");
fruits.stream()
    .filter(f -> f.length() > 5)
    .peek(System.out::println)
    .collect(Collectors.toList());

中间操作的示例代码:

List<String> items = Arrays.asList("apple", "banana", "orange", "kiwi");
 
// Filtering
List<String> filteredItems = items.stream()
    .filter(item -> item.startsWith("a"))
    .collect(Collectors.toList());

// Sorting
List<String> sortedItems = items.stream()
    .sorted()
    .collect(Collectors.toList());
 
// Distinct
List<String> distinctItems = items.stream()
    .distinct()
    .collect(Collectors.toList());
 
// Limiting
List<String> limitedItems = items.stream()
    .limit(2)
    .collect(Collectors.toList());
 
// Skipping
List<String> skippedItems = items.stream()
    .skip(1)
    .collect(Collectors.toList());

在这里插入图片描述

函数式编程,在流管道中可以包含0个或n个中间操作,每个中间操作都返回一个新的流。

二、中间操作 映射器map()的用法

映射器map的方法签名(原型):

  • map(Function<? super T, ? extends R> mapper) - 它的输入参数是一个类型为函数接口的映射器,可将流中的元素转换成其他类型的元素。映射器map()是把一个对象流变成另一种对象流。

另外三个与映射器map()类似的映射器,它们则可以把一个对象流转换为基本类型流。

  • mapToInt(ToIntFunction<? super T> mapper) - 将元素映射为值的整型int流。
  • mapToLong(ToLongFunction<? super T> mapper) - 将元素映射为值的长整型long流。
  • mapToDouble(ToDoubleFunction<? super T> mapper) - 将元素映射为值的双精度浮点型double流。

在这里插入图片描述

用法一:将一种流映射成另一种流

把英文的小写转换为大写的代码片断:

// Mapping
List<String> items = Arrays.asList("apple", "banana", "orange", "grape");
List<String> mappedItems = items.stream()
    .map(String::toUpperCase)
    .collect(Collectors.toList());

下面是来看一个完整的示例。下图是这个流管道的详细分解说明图示:
在这里插入图片描述

这个示例完整的程序源码:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MapTest {
	public static void main(String[] args) {
		List<User> list = Arrays.asList(new User(2001, "Ricky"), new User(2002, "Alex"), new User(2003, "Bob"));
		list.forEach(System.out::println);
		List<String> newList = list.stream().map(User::getName).sorted().limit(2).collect(Collectors.toList());
		newList.forEach(System.out::println);
	}
}

class User {
	private int id;
	private String name;
	public User(int id,String name) {
		this.id = id;
		this.name = name;
	}
	public String getName() {
		return name;
	}
	@Override
	public String toString() {
		return "{User[ID:"+id+" 姓名:"+name+"]}";
	}
}

例程测试效果图:
在这里插入图片描述
映射器map示例: 实现功能:整数列表每个元素+3。分别用对象流和IntStream来实现。
使用的两个映射器的原型如下所示:

//本示例使用的map()方法的签名,其入口参数类型是Function函数,如下:
<Integer> Stream<Integer> java.util.stream.Stream.map(Function<? super Integer, ? extends Integer> mapper)
//本示例使用的mapToInt()方法的签名,其入口参数类型是ToIntFunction函数,如下
IntStream java.util.stream.Stream.mapToInt(ToIntFunction<? super Integer> mapper)

这两个流,尽管入口参数的函数类型不一样,但完全可以用同一个Lambda表达式来代替函数接口的实例作为传入参数。
但后续的处理方式有些不同:映射器map()返回的是对象流,可用收集器collect(Collectors.toList())来收集结果。映射器mapToInt()返回的是IntStream(整型流),不能使用用收集器。因为收集器收集的元素必须是对象,IntStream中的元素是基本数据类型,所以收集器不支持。

		List<Integer> intList = Arrays.asList(1, 3, 5, 7, 9, 11);

		//对象流的实现方式
		List<Integer> intListNew = intList.stream().map(x -> x + 3).collect(Collectors.toList());
		System.out.println("每个元素+3:" + intListNew);

		//用IntStream来实现
		System.out.println("打印IntStream:");
		IntStream intStream = intList.stream().mapToInt(x -> x + 3);
		intStream.forEach(System.out::println);

测试效果图:
在这里插入图片描述
mapToDouble基本数据类型流例程
基本数据类型流,比如DoubleStream(双精度浮点型流)不能使用收集器收集结果,但也有很多的终止操作,比如求最大最小值、求和、求平均值:

public static void main(String[] args) {
    List<Double> doubleList = Arrays.asList(1.0, 22.0, 3.0, 4.0, 32.0);
    double average = doubleList.stream().mapToDouble(Number::doubleValue).average().getAsDouble();
    double sum = doubleList.stream().mapToDouble(Number::doubleValue).sum();
    double max = doubleList.stream().mapToDouble(Number::doubleValue).max().getAsDouble();
    System.out.println("平均值:" + average + ",总和:" + sum + ",最大值:" + max);
}

测试结果: 平均值:12.4,总和:62.0,最大值:32.0

三、中间操作 摊平映射器flatMap()的用法

  • flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) - 将每个元素转换为某种元素类型的流,然后将它们连接成一个流。

在这里插入图片描述

摊平映射器flatMap()示例一:

public class StreamTest {
	public static void main(String[] args) {
		List<String> list = Arrays.asList("m,k,l,a", "1,3,5,7");
		List<String> listNew = list.stream().flatMap(s -> {
			// 将每个元素转换成一个stream
			String[] split = s.split(",");
			return Arrays.stream(split);
		}).collect(Collectors.toList());

		System.out.println("处理前的集合:" + list);
		System.out.println("处理后的集合:" + listNew);
	}
}

在这个例子中,初始时对象流的元素类型是长度为7的字符串:“m,k,l,a"和"1,3,5,7”。[ “m,k,l,a” , “1,3,5,7” ]。通过摊平映射器flatMap()转换后的对象流的元素类型是长度为1的字符串。最终对象流为[ “m” , “k” , “l” , “a” , “1” , “3” , “5” , “7” ]

实际上,上面的示例程序还可以简化,可简化为:

	List<String> listNew = list.stream().flatMap(str->Stream.of(str.split(","))).collect(Collectors.toList());

摊平映射器flatMap()示例二:

package stream;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class FlatMapTest {
	public static void test1() {
		List<String> items = Arrays.asList("glass", "brick","gold", "silver");
		List<String> flatMappedItems = items.stream().flatMap(item -> Stream.of(item.split(""))).collect(Collectors.toList());
		flatMappedItems.forEach(System.out::println);
	}

	public static void test2() {
		String songs = "Remember me to one who lives there";
		String[] words = songs.split(" ");
		List<String> strList = Arrays.stream(words).map(s -> s.split("e"))
				.flatMap(e -> Arrays.stream(e))
				.collect(Collectors.toList());
		strList.forEach(System.out::println);
	}
	public static void main(String[] args) {
		test1();
		test2();
	}
}

测试结果图:
在这里插入图片描述
流的连接:有两种方式。如果是两个流的连接,可使用 Stream.concat() 方法;
如果是三个及三个以上流的连接,就使用 摊平映射器flatMap() 方法。
摊平映射器flatMap还可以用来实现流的连接,请看例程:

	public static void concatStream() {
		String names[][] = { {"Alice", "Alien", "Bob"},
			{"Jack", "John", "Jobs"},{"Maria", "Golf", "Korea"} };
        //两个流的连接
        Stream<String> concat = Stream.concat(Arrays.stream(names[0]), Arrays.stream(names[1]));
        concat.forEach(System.out::println);
        System.out.println("===========");
        //多个流的连接,例子之一
        List<String[]> list = Arrays.asList(names);
        Stream<String> strStream = list.stream().flatMap(e->Arrays.stream(e));
        strStream.forEach(System.out::println);
        
        System.out.println("===========");
        Stream<String> first = Stream.of("Alice", "Alien", "Bob");
        Stream<String> second = Stream.of("Jack", "John", "Jobs");
        Stream<String> third = Stream.of("Maria", "Golf", "Korea");
        //多个流的连接,例子之二
        //Stream<String> stringStream = Stream.of(first, second, third).flatMap(s->s);
        Stream<String> stringStream = Stream.of(first, second, third).flatMap(Function.identity());
        stringStream.forEach(System.out::println);
	}

说明: 多个流的连接,“例子之一”和“例子之二”实现相同功能。另外,示例中“flatMap(Function.identity())”等价于“flatMap(s->s)”。

摊平映射器有很多,例如摊平为基本数据类型流的映射器(可由类型T的对象流转换为基本数据类型的流):

  • IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
  • LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
  • DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);

映射器map和flatMap的区别

map()操作将每个元素转换成一个新元素,并将所有这些新生成的元素收集到一个新的流中。
flatMap()操作将每个元素转换成一个新的流,并将所有这些新生成的流合并成一个单一的流。
flatMap()和map()之间还有一个重要的区别,那就是flatMap()支持处理包含嵌套数据结构的流。

参考文献:

  • Java8 Stream:2万字20个实例,玩转集合的筛选、归约、分组、聚合-CSDN
  • 恕我直言你可能真的不会java系列-CSDN
  • Java8 Stream流使用-CSDN
  • Java 8 Stream API:从基础到高级,掌握流处理的艺术
  • JAVA8专题-Stream流操作详解
  • Java 8新特性Stream()流
  • Java8 特性笔记(四) Stream

第1篇:lambda表达式会用了么?
第2篇:Java Stream API?
第3篇:Stream的Filter与谓词逻辑
第4篇:Stream管道流Map操作
第5篇:Stream的状态与并行操作
第7篇:像使用SQL一样排序集合
第8篇-函数式接口
第9篇-元素的匹配与查找
第10篇-集合元素归约
第11篇-Stream API终端操作

Java Stream函数式编程第三篇:管道流结果处理

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用pymupdf提取PDF文档中的文字和其颜色

最近我在捣鼓一个PDF文件&#xff0c;想把它里面的文字和文字颜色给提取出来。后来发现有个叫pymupdf的库能搞定这事儿。操作起来挺简单的&#xff0c;pymupdf的示例文档里就有现成的代码可以参考。 how-to-extract-text-with-color 我本地的测试代码如下&#xff1a; impor…

MYSQL 多表练习

Sutdent表的定义 ---------------------------------------------------------------------------------------------------- | 字段名 | Id | Name | Sex | Birth | Department | Address | -------------------…

2024年12月HarmonyOS应用开发者基础认证全新题库

注意事项&#xff1a;切记在考试之外的设备上打开题库进行搜索&#xff0c;防止切屏三次考试自动结束&#xff0c;题目是乱序&#xff0c;每次考试&#xff0c;选项的顺序都不同 更新时间&#xff1a;2024年12月3日 这是基础认证题库&#xff0c;不是高级认证题库注意看清楚标…

一文解析Kettle开源ETL工具!

ETL&#xff08;Extract, Transform, Load&#xff09;工具是用于数据抽取、转换和加载的软件工具&#xff0c;用于支持数据仓库和数据集成过程。Kettle作为传统的ETL工具备受用户推崇。本文就来详细说下Kettle。 一、Kettle是什么&#xff1f; Kettle 是一款开源的 ETL&#x…

【模型剪枝】YOLOv8 模型剪枝实战 | 稀疏化-剪枝-微调

文章目录 0. 前言1. 模型剪枝概念2. 模型剪枝实操2.1 稀疏化训练2.2 模型剪枝2.3 模型微调总结0. 前言 无奈之下,我还是写了【模型剪枝】教程🤦‍♂️。回想当年,在写《YOLOv5/v7进阶实战专栏》 时,我经历了许多挫折,才最终完成了【模型剪枝】和【模型蒸馏】的内容。当时…

【算法刷题指南】优先级队列

&#x1f308;个人主页&#xff1a; 南桥几晴秋 &#x1f308;C专栏&#xff1a; 南桥谈C &#x1f308;C语言专栏&#xff1a; C语言学习系列 &#x1f308;Linux学习专栏&#xff1a; 南桥谈Linux &#x1f308;数据结构学习专栏&#xff1a; 数据结构杂谈 &#x1f308;数据…

大语言模型微调与 XTuner 微调实战

1 大语言模型微调 1.1 什么是微调 大语言模型微调&#xff08;Fine-tuning of Large Language Models&#xff09;是指在预训练的大型语言模型基础上&#xff0c;使用特定任务的数据进一步训练模型&#xff0c;以使其更好地适应和执行特定任务的过程&#xff0c;用于使LLM&am…

C#学写了一个程序记录日志的方法(Log类)

1.错误和警告信息单独生产文本进行记录&#xff1b; 2.日志到一定内存阈值可以打包压缩&#xff0c;单独存储起来&#xff0c;修改字段MaxLogFileSizeForCompress的值即可&#xff1b; 3.Log类调用举例&#xff1a;Log.Txt(JB.信息,“日志记录内容”,"通道1"); usi…

【前端】特殊案例分析深入理解 JavaScript 中的词法作用域

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;案例代码&#x1f4af;词法作用域&#xff08;Lexical Scope&#xff09;与静态作用域什么是词法作用域&#xff1f;代码执行的详细分析 &#x1f4af;函数定义与调用的…

【Docker】Docker配置远程访问

配置Docker的远程访问&#xff0c;你需要按照以下步骤进行操作&#xff1a; 1. 在Docker宿主机上配置Docker守护进程监听TCP端口 Docker守护进程默认只监听UNIX套接字&#xff0c;要实现远程访问&#xff0c;需要修改配置以监听TCP端口。 ‌方法一&#xff1a;修改Docker服务…

贪心算法题

0简介 0.1什么是贪心算法 贪心算法是用贪婪(鼠目寸光)的角度&#xff0c;找到解决问题的最优解 贪心策略&#xff1a;(从局部最优 --> 整体最优) 1把解决问题的过程分为若干步&#xff1b; 2解决每一个问题时&#xff0c;都选择当前“看上去”最优的解法&#xff1b; 3“…

【HTTP】HTTP协议

一个Web Server就是个服务器软件&#xff08;程序&#xff09;&#xff0c;或者是运行这个服务器软件的硬件&#xff08;计算机&#xff09;&#xff0c;其主要功能是通过HTTP协议与客户端进行通信&#xff0c;来接收&#xff0c;存储&#xff0c;处理来自客户端的HTTP请求&…

分布式存储方式的地理信息数据仓库建立设计方案

背景介绍 随着地理信息技术的发展,GIS系统中的数据规模越来越庞大,传统集中式存储方式在处理高并发查询和大规模空间分析时面临瓶颈。分布式存储通过数据分片、并行计算等技术,为地理信息数据管理提供了新的解决方案。适用场景: 遥感影像存储与分析 城市交通数据管理(如G…

深度学习案例:ResNet50模型+SE-Net

本文为为&#x1f517;365天深度学习训练营内部文章 原作者&#xff1a;K同学啊 一 回顾ResNet模型 ResNet&#xff0c;即残差网络&#xff0c;是由微软研究院的Kaiming He及其合作者于2015年提出的一种深度卷积神经网络架构。该网络架构的核心创新在于引入了“残差连接”&…

droppath

DropPath 是一种用于正则化深度学习模型的技术&#xff0c;它在训练过程中随机丢弃路径&#xff08;或者说随机让某些部分的输出变为零&#xff09;&#xff0c;从而增强模型的鲁棒性和泛化能力。 代码解释&#xff1a; import torch import torch.nn as nn # 定义 DropPath…

KAN-Transfomer——基于新型神经网络KAN的时间序列预测

1.数据集介绍 ETT(电变压器温度)&#xff1a;由两个小时级数据集&#xff08;ETTh&#xff09;和两个 15 分钟级数据集&#xff08;ETTm&#xff09;组成。它们中的每一个都包含 2016 年 7 月至 2018 年 7 月的七种石油和电力变压器的负载特征。 traffic(交通) &#xff1a;描…

03-12、SpringCloud Alibaba第十二章,升级篇,服务注册与配置中心Nacos

SpringCloud Alibaba第十二章&#xff0c;升级篇&#xff0c;服务注册与配置中心Nacos 一、为什么SpringCloud Alibaba 1、为什么 有了spring cloud这个微服务的框架&#xff0c;为什么又要使用spring cloud alibaba这个框架了&#xff1f;最重要的原因在于spring cloud中的…

算法之旅:LeetCode 拓扑排序由简入繁完全攻略

前言 欢迎来到我的算法探索博客&#xff0c;在这里&#xff0c;我将通过解析精选的LeetCode题目&#xff0c;与您分享深刻的解题思路、多元化的解决方案以及宝贵的实战经验&#xff0c;旨在帮助每一位读者提升编程技能&#xff0c;领略算法之美。 &#x1f449;更多高频有趣Lee…

MATLAB 离散点构建凸包,计算面积周长(88)

MATLAB 离散点构建凸包,计算面积周长(88) 一、算法介绍二、算法实现1.代码2.总结这是缘,亦是命中最美的相见!!! 一、算法介绍 给定一堆离散点云,构建二维凸包,并计算凸包的面积和周长。 凸包是由顺序顶点构成的,因此凸包也可以当作多边形,则例的面积和周长计算方法…

Matlab Simulink HDL Coder开发流程(一)— 创建HDL兼容的Simulink模型

创建HDL兼容的Simulink模型 一、使用Balnk DUT模板二、从HDL Coder库中选择模块三、为DUT开发算法/功能四、为设计创建Testbench五、仿真验证设计功能六、Simulink模型生成HDL代码 这个例子说明了如何创建一个用于生成HDL代码的Simulink模型。要创建兼容HDL代码生成的MATLAB算法…