JAVA进阶 —— Steam流

news2024/11/29 10:41:33

目录

一、 引言

二、 Stream流概述

三、Stream流的使用步骤

 1.  获取Stream流

1.1  单列集合

1.2  双列集合

1.3  数组

1.4  零散数据

2. Stream流的中间方法

3. Stream流的终结方法

四、 练习

1.  数据过滤

2.  数据操作 - 按年龄筛选

3. 数据操作 - 演员信息要求筛选


一、 引言

初识Stream流的作用:

需求:按照下面的要求完成集合的创建和遍历,创建一个集合,存储多个字符串元素

 通过下面代码,显然我们清晰的看到使用Stream流更为方便,而使用不同的集合遍历就有些复杂。

public class Test01 {
	public static void main(String[] args) {
		ArrayList<String> list1 = new ArrayList<>();
		list1.add("张无忌");
		list1.add("周正若");
		list1.add("赵斌");
		list1.add("张强");
		list1.add("张三丰");

		// Stream流
		list1.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3)
				.forEach(name -> System.out.println(name));
		// 张无忌
		// 张三丰

		// 1.把所有“张”姓开头元素存储到新集合
		ArrayList<String> list2 = new ArrayList<>();
		for (String name : list1) {
			if (name.startsWith("张")) {
				list2.add(name);
			}
		}
		System.out.println(list2); // [张无忌, 张强, 张三丰]

		// 2.把所有“张”姓开头且长度为3的元素存储到新集合
		ArrayList<String> list3 = new ArrayList<>();
		for (String name : list2) {
			if (name.length() == 3) {
				list3.add(name);
			}
		}
		System.out.println(list3); // [张无忌, 张三丰]
	}
}

二、 Stream流概述

例如上面的小例子,Stream流的思想如下:

顺序筛选

 Stream流的作用:

 结合了Lambda表达式,简化集合、数字的操作。

三、Stream流的使用步骤

  1. 先得到一条Stream流(流水线),并把数据放上去。
  2. 使用中间方法对流水线上的数据进行操作。
  3. 使用终结方法对流水线上的数据进行操作。
过滤、转换中间方法方法调用完毕之后,还可以调用其他方法
统计、打印终结方法最后一步,调用完毕之后,不能调用其他方法

 1.  获取Stream流

获取方式方法名说明
单列集合default  Stream<E>  stream()Collection中的默认方法
双列集合

无法直接使用stream流,需要通过keySet()或者entrySet()变成单列集合

数组public  static <T>  Stream <T>  stream(T [ ] array)Arrays工具类中的静态方法
一堆零散数据public  static <T>  Stream <T>  of(T... values)stream接口中的静态方法

1.1  单列集合

public class StreamTest {
	public static void main(String[] args) {
		//单列集合获取Stream流
		ArrayList<String> list = new ArrayList<>();
		Collections.addAll(list, "a","b","c","d","e");
		//获取到一个流水线,并把集合中的数据方法流水线上
		//Stream<String> stream1 = list.stream();
		//使用终结方法打印流水线上数据
		//stream1.forEach( s ->System.out.println(s) );
		
		list.stream().forEach(s -> System.out.println(s));
	}
}

1.2  双列集合

public class StreamTest {
	public static void main(String[] args) {
		
		//双列集合获取Stream流 
		//1. 创建双列集合
		HashMap<String, Integer> hm = new HashMap<>();
		//2. 添加数据
		hm.put("aaa", 111);
		hm.put("bbb", 222);
		hm.put("ccc", 333);
		//3.1 获取Stream流方法一: keySet()
		//键
		 hm.keySet().stream().forEach(s -> System.out.println(s));
		//3.2 获取Stream流方法二:entrySet()
		 //键值对
		hm.entrySet().stream().forEach(s -> System.out.println(s));	 
	}
}

1.3  数组

Stream接口中静态方法of的细节:

  • 方法的形参是一个可变参数,可以传递一堆零散数据,也可以传递数组。
  • 但是数组必须是引用数据类型。
  • 如果传递的是基本数据类型,是会把整个数组相当做一个元素,放到一个stream流当中。
public class StreamTest {
	public static void main(String[] args) {
		
		//数组获取Stream流 
		//1.创建基本数据类型数组
		int[] arr1 = {1,2,3,4,5,6,7,8,9,10};
		//获取stream
		Arrays.stream(arr1).forEach(s -> System.out.println(s));
		
		//2.创建引用数据类型数组
		String[] arr2 = {"a","b","c"};
		//获取stream
		Arrays.stream(arr2).forEach(s -> System.out.println(s));
		
		//方式是错误的!!!
		//Stream接口中静态方法of的细节
		//方法的形参是一个可变参数,可以传递一堆零散数据,也可以传递数组
		//但是数组必须是引用数据类型
		//如果传递的是基本数据类型,是会把整个数组相当做一个元素,放到一个stream流当中
		Stream.of(arr2).forEach(s -> System.out.println(s));
		Stream.of(arr1).forEach(s -> System.out.println(s)); //[I@1b28cdfa
	}
}

1.4  零散数据

细节: 一堆零散数据需要是相同的数据类型。

public class StreamTest {
	public static void main(String[] args) {
		//零散数据获取Stream流 
		
		//基本数据类型
		Stream.of(1,2,3,4,5).forEach(s -> System.out.println(s));
		
		//引用数据类型
		Stream.of("a","b","c","d","e").forEach(s -> System.out.println(s));
	}
}

2. Stream流的中间方法

方法名称说明
Stream<T> filter ( Predicate<? super T>  predicate )过滤
Stream<T> limit ( long  maxSize)获取前几个元素
Stream<T> skip ( long  n )跳过前几个元素
Stream<T> distinct ( )元素去重,依赖(hashCode和equals方法)
static <T> Stream<T> concat ( Stream a ,  Stream b )合并a和b两个流为一个流
Stream<R> map ( Function<T ,R>  mapper )转换流中的数据类型

注意一:中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程。

注意二:修改Stream流中的数据,不会影响原来集合或者数组中的数据。

public class StreamTest01 {
	public static void main(String[] args) {
		//1.过滤:把开头的留下,其余数据过滤不要
		ArrayList<String> list = new ArrayList<>();
		Collections.addAll(list, "张三","李四","王五","赵六","张七");
		
		ArrayList<String> list2 = new ArrayList<>();
		Collections.addAll(list2, "张三","李四","王五","赵六","张三");
		
		ArrayList<String> list3 = new ArrayList<>();
		Collections.addAll(list3, "孙七","钱八");
		
		ArrayList<String> list4 = new ArrayList<>();
		Collections.addAll(list2, "张三-23","李四-24","王五-25");
		
		list.stream().filter(new Predicate<String>() {
			//匿名内部类太麻烦 需要缩写
			@Override
			public boolean test(String s) {
				//如果返回值为true,表示当前数据留下
				//如果返回值为false,表示当前数据舍弃
				return s.startsWith("张");
				
			}
		}).forEach(s -> System.out.println(s)); //张三 张七
		
		list.stream()
		    .filter(s -> s.startsWith("张"))
		    .forEach(s -> System.out.println(s));
		
		//2. 获取前几个元素  
		list.stream()
		    .limit(3)
		    .forEach(s -> System.out.println(s));  //张三 李四 王五
		//3. 跳过
		list.stream()
		    .skip(4)
		    .forEach(s -> System.out.println(s));  //张七
		
		//4.去重
		list2.stream()
		     .distinct()
		     .forEach(s -> System.out.println(s)); //张三 李四 王五 赵六
		
		//5. 合并
		Stream.concat(list2.stream(), list3.stream())
		      .forEach(s -> System.out.println(s));
		
		//6.转换数据类型
		//只能获取集合里面的年龄并打印
		//第一个类型:流中原本的数据类型
		//第二个类型:将要转变成为的数据类型
		list4.stream().map(new Function<String,Integer>() {
			@Override
			//apply: 依次表示流中的每一盒数据
			//返回值:表示转化之前的数据
			public Integer apply(String s) {
				String[] arr = s.split("-");
				String ageString = arr[1];
				int age = Integer.parseInt(ageString);
				return age;
			}
		}).forEach(s -> System.out.println(s));
		
		list.stream()
		    .map(s ->Integer.parseInt(s.split("-")[1]))
		    .forEach(s -> System.out.println(s));
	}
}

3. Stream流的终结方法

方法名称说明
void forEach ( Consumer action )遍历
long count ( )统计
toArray ( )收集流中的数据,放到数组中
collect ( Collector collector )收集流中的数据,放到集合中
public class StreamTest02 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		Collections.addAll(list, "张三", "李四", "王五", "赵六");

		// 遍历

		// Consumer的泛型:表示流中的数据类型
		// accept方法的形参s:依次表示流中的每一个数据
		//
		list.stream().forEach(new Consumer<String>() {
			@Override
			public void accept(String s) {
				System.out.println(s);
			}
		});

		list.stream().forEach(s -> System.out.println(s)); // 张三 李四 王五 赵六

		// 统计
		long count = list.stream().count();
		System.out.println(count); // 4

		// 收集数据放进数组
		Object[] arr1 = list.stream().toArray();
		System.out.println(Arrays.toString(arr1)); // [张三, 李四, 王五, 赵六]

		// 指定数据类型
		// Infunction的泛型:具体类型的数组
		// apply中形参:流中数据的个数,要跟数组长度一致
		// apply的返回值:具体类型的数组
		String[] arr2 = list.stream().toArray(new IntFunction<String[]>() {
			@Override
			public String[] apply(int value) {
				return new String[value];
			}
		});
		// toArray方法中的参数:只是创建一个指定类型的数组
		// toArray底层: 会此意得到流中的每一个数据,并把数据放到数组中
		// toArray的返回值:是一个装着流里面所有数据的数组
		System.out.println(Arrays.toString(arr2));

		// lambda表达式
		String[] arr3 = list.stream().toArray(value -> new String[value]);
		System.out.println(Arrays.toString(arr3));
	}
}

 collect方法:

public class StreamTest {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<>();
		Collections.addAll(list, "张三-男-23", "李四-男-24", 
                        "王五-男-25", "赵六-女-27", "孙八-女-28");

		//收集到List集合当中
		//需求:
		//将所有的男性收集起来
		List<String> newList = list.stream()
				.filter(s-> "男".equals(s.split("-")[1]))
				.collect(Collectors.toList());
		System.out.println(newList);  //[张三-男-23, 李四-男-24, 王五-男-25]
		
		//收集到Set集合当中
		Set<String> newSet = list.stream()
				.filter(s-> "男".equals(s.split("-")[1]))
				.collect(Collectors.toSet());
		System.out.println(newSet);
		
		//收集到Map集合当中
		//键: 姓名  值: 年龄
		
		//toMap:
		//参数一表示键的生成规则  参数二表示值得生成规则
		//参数一:  
		//Function泛型一:表示流中每一个数据的类型 ;
		//        泛型二:表示Map集合中键的数据类型
		//方法apply 形参:一次表示流里面的每一个数据
		//        方法体:生成键的代码 
		//        返回值:已生成的键
		//参数二:
		//Function泛型一:表示流中每一个数据的类型 ;
		//        泛型二:表示Map集合中值的数据类型
		//方法apply 形参:一次表示流里面的每一个数据
		//        方法体:生成值的代码 
		//        返回值:已生成的值
		Map<String, Integer> newMap = list.stream()
		.filter(s-> "男".equals(s.split("-")[1]))
		.collect(Collectors.toMap(new Function<String, String>() {
			@Override
			public String apply(String s) {
				return s.split("-")[0];
			}
		}, new Function<String, Integer >() {
			@Override
			public Integer apply(String s) {
				return Integer.parseInt(s.split("-")[2]);
			}
		}));
		System.out.println(newMap);  //{李四=24, 张三=23, 王五=25}
		
		//lambda表达式
		Map<String, Integer> newMap1 = list.stream()
				.filter(s-> "男".equals(s.split("-")[1]))
				.collect(Collectors.toMap( 
						s-> s.split("-")[0], 
						s-> Integer.parseInt(s.split("-")[2])));
		System.out.println(newMap1);
	}
}

四、 练习

1.  数据过滤

需求:

定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10

过滤奇数,只留下偶数。
并将结果保存起来

public class StreamDemo {
	public static void main(String[] args) {
		// 1.定义一个集合
		ArrayList<Integer> list = new ArrayList<>();
		// 2.添加数据
		Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

		// 3.过滤奇数,只留偶数
		// 进行判断,如果是偶数,返回true
		List<Integer> list2 = list.stream()
				.filter(n -> n % 2 == 0)
				.collect(Collectors.toList());
		System.out.println(list2); //[2, 4, 6, 8, 10]
	}
}

2.  数据操作 - 按年龄筛选

需求:
创建一个ArrayList集合,并添加以下字符串,字符串中前面是姓名,后面是年龄

      “zhangsan,23”
      “lisi,24"
      “wangwu,25”
保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值

public class StreamDemo {
	public static void main(String[] args) {
		// 1.定义一个集合
		ArrayList<String> list = new ArrayList<>();
		//2.集合添加字符串
		list.add( "zhangsan,23");
		list.add("lisi,24");
		list.add("wangwu,25");
		//3.保留年龄大于24岁的人
		Map<String, Integer> map = list.stream()
		.filter(s -> Integer.parseInt(s.split(",")[1]) >= 24)
		.collect(Collectors.toMap(
				s -> s.split(",")[0], 
				s -> Integer.parseInt(s.split(",")[1])));
		System.out.println(map);  //{lisi=24, wangwu=25}
	}
}

3. 数据操作 - 演员信息要求筛选

现在有两个ArrayList集合,
第一个集合中:存储6名男演员的名字和年龄。第二个集合中:存储6名女演员的名字和年龄。姓名和年龄中间用逗号隔开。比如:张三,23
要求完成如下的操作:

  1. 男演员只要名字为3个字的前两人
  2. 女演员只要姓杨的,并且不要第一个
  3. 把过滤后的男演员姓名和女演员姓名合并到一起
  4. 将上一步的演员信息封装成Actor对象。
  5. 将所有的演员对象都保存到List集合中。

备注:演员类Actor,属性有:name,age

public class StreamDemo {
	public static void main(String[] args) {
		// 1.定义两个集合
		ArrayList<String> manList = new ArrayList<>();
		ArrayList<String> womenList = new ArrayList<>();

		// 2.添加数据
		Collections.addAll(manList, "蔡坤坤,24", "叶购成,23", "刘不甜,22", "吴签,24", "谷嘉,30", "肖梁梁,27");
		Collections.addAll(womenList, "赵小颖,35", "杨颖,36", "高元元,43", "张天天,31", "刘诗,35", "杨小幂,33");

		// 3. 男演员只要名字为3个字的前两个人
		Stream<String> stream1 = manList.stream()
		.filter(s -> s.split(",")[0].length() == 3)
		.limit(2);
//		.forEach(s -> System.out.println(s)); // 蔡坤坤,24  叶购成,23
																													// 叶购成,23
		//4.女演员只要姓杨的 并且不要第一个
		Stream<String> stream2 = womenList.stream()
		.filter(s -> s.split(",")[0].startsWith("杨"))
		.skip(1);
//		.forEach(s -> System.out.println(s));  //杨小幂,33
		
		//5.把过滤的男演员和女演员信息合并在一起
		//演员信息封装进Actor对象
		
		//String -> Actor对象(类型转换)
		List<Actor> list = Stream.concat(stream1, stream2)
		.map(s -> new Actor(s.split(",")[0],Integer.parseInt(s.split(",")[1])))
		.collect(Collectors.toList());
		System.out.println(list);
	}
}

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

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

相关文章

mysql创建索引导致死锁,数据库崩溃,完美解决方案

文章目录写在前面一、短事务场景下&#xff0c;执行DDL语句场景分析1、短事务场景下&#xff0c;执行表字段添加操作2、短事务场景下&#xff0c;执行表字段修改操作3、短事务场景下&#xff0c;执行表字段删除操作&#xff08;1&#xff09;往里添加一条数据试试4、短事务场景…

操作系统内核与安全分析课程笔记【2】进程管理与调度

文章目录基本概念与关键数据结构进程管理进程生命周期进程的关系进程家族树线程组进程组与会话进程的创建与终止Linux中的线程基本概念与关键数据结构 进程&#xff1a;静态的&#xff0c;存储在磁盘上的代码与数据。 程序&#xff1a;动态的&#xff0c;执行程序的动态过程&am…

线程调度的基本过程

进程的基本调度过程 文章目录进程的基本调度过程一.什么是进程我们先用官方的话语去解释一下,大家先看我们对这个定义的一个结果如下:二.进程的特征三.进程的三种基本状态四.进程的管理4.1 什么是PCB4.2 PCB中的信息4.2.1 pid4.2.2 内存指针4.2.3文件描述符4.2.4 进程调度信息一…

【Android】aliyun云构建自动化打包

先贴出 阿里云移动研发平台EMAS-云构建的文档地址 一切以文档为主 简介 云构建服务支持通过流水线进行多端应用的编译构建任务&#xff0c;支持包签名、平台托管证书等能力&#xff0c;提升研发效率&#xff0c;规范研发流程。 提升研发效能&#xff0c;缩短交付周期 提升研发…

【专项训练】布隆过滤器和LRU缓存

布隆过滤器:与哈希表类似 哈希表是一个没有误差的数据结构! 有哈希函数得到index,会把要存的整个元素放在哈希表里面 有多少元素,每个元素有多大,所有的这些元素需要占的内存空间,在哈希表中都要找相应的内存大小给存起来 事实上,我们并不需要存所有的元素本身,而是只…

C++模拟实现红黑树

目录 介绍----什么是红黑树 甲鱼的臀部----规定 分析思考 绘图解析代码实现 节点部分 插入部分分步解析 ●父亲在祖父的左&#xff0c;叔叔在祖父的右&#xff1a; ●父亲在祖父的右&#xff0c;叔叔在祖父的左&#xff1a; 测试部分 整体代码 介绍----什么是红黑树 红…

5.2 对射式红外传感器旋转编码器计次

对射式红外传感器1.1 接线图VCC GND分别接电源的正负极DO数字输出端&#xff0c;随意选择一个GPIO口1.2 硬件原理当挡光片或者编码盘在对射式红外传感器中间经过时&#xff0c;DO就会输出电平变化信号&#xff0c;电平跳变信号触发STM32 PB14号口中断&#xff0c;在中断函数中执…

01: 新手学SpringCloud前需知道的5点

目录 第一点&#xff1a; 什么是微服务架构 第二点&#xff1a;为什么需要学习Spring Cloud 第三点&#xff1a; Spring Cloud 是什么 第四点&#xff1a; SpringCloud的优缺点 1、SpringCloud优点 2、SpringCloud缺点 第五点&#xff1a; SpringCloud由什么组成 1&…

数据结构——链表OJ题目讲解(2)

作者&#xff1a;几冬雪来 时间&#xff1a;2023年3月10日 内容&#xff1a;数据结构链表OJ题目讲解 来源&#xff1a;牛客网和力扣 目录 前言&#xff1a; 刷题&#xff1a; 1.反转链表&#xff1a; 1.改变指向的解法&#xff1a; 2.取头结点插入到新链表&#xff1a; …

参考 | 辨别真假笔记本三星内存条 (ddr4)

参考 | 辨别真假笔记本三星内存条 (ddr4) 文章目录参考 | 辨别真假笔记本三星内存条 (ddr4)1. 三星内存条标签纸上编码的含义2. 三星内存颗粒上编码的含义3. 辨别内容参考1. 三星内存条标签纸上编码的含义 内存条贴张上面有两串值得注意的编码, 其中编码的具体意义参考三星官方…

docker-compress 配置

文章目录docker-compress下载安装常用命令Docker Compose配置常用字段docker compose案例yml 配置指令参考versionbuildcap_add&#xff0c;cap_dropcgroup_parentcommandcontainer_namedepends_ondeploydevicesdnsdns_searchentrypointenv_fileenvironmentexposeextra_hostshe…

【3.10】操作系统进程管理、KMP算法

多线程冲突了怎么办&#xff1f; 由于多线程执行操作共享变量可能会导致竞争状态&#xff0c;因此我们将此段代码称为临界区&#xff08;*critical section*&#xff09;&#xff0c;它是访问共享资源的代码片段&#xff0c;一定不能给多线程同时执行。 我们希望这段代码是互斥…

cadence skill 记录FPM不能保存问题

;FPM skill by Richard L. version0.08 fpmontrealgmail.com;Tree:杂项(Chinese)/简单范例;Desc:范例如何建立一个简单的二极管封装;Vendor:Richard L.;Count:1;CVG64:示意图字段(测试中);Datasheet:pL12.7 ;引脚间距pA7.6 pB3.5 pH3.5 ;长宽高pPad2.0 pHole1.2 ;焊盘直径和孔径…

论文阅读《Block-NeRF: Scalable Large Scene Neural View Synthesis》

论文地址&#xff1a;https://arxiv.org/pdf/2202.05263.pdf 复现源码&#xff1a;https://github.com/dvlab-research/BlockNeRFPytorch 概述 Block-NeRF是一种能够表示大规模环境的神经辐射场&#xff08;Neural Radiance Fields&#xff09;的变体&#xff0c;将 NeRF 扩展到…

渗透测试——信息收集(详细)

信息收集&#xff1a;前言&#xff1a;信息收集是渗透测试除了授权之外的第一步&#xff0c;也是关键的一步&#xff0c;尽量多的收集目标的信息会给后续的渗透事半功倍。收集信息的思路有很多&#xff0c;例如&#xff1a;页面信息收集、域名信息收集、敏感信息收集、子域名收…

Redis学习【12】之Redis 缓存

文章目录前言一 Jedis 简介二 使用 Jedis2.1 测试代码2.2 使用 JedisPool2.3 使用 JedisPooled2.4 连接 Sentinel 高可用集群2.5 连接分布式系统2.6 操作事务三 Spring Boot整合Redis3.1 创建工程3.2 定义 pom 文件3.3 完整代码3.4 总结四 高并发问题4.1 缓存穿透4.2 缓存击穿4…

全方位解读智能中控屏发展趋势!亚马逊Alexa语音+Matter能力成必备

随着智能家居行业逐步从碎片化的智能单品阶段&#xff0c;迈向体验更完整的全屋互联阶段&#xff0c;智能中控屏作为智能家居最佳的入口之一&#xff0c;在年轻人青睐全屋智能装修的风潮下&#xff0c;市场潜力彻底被引爆。 一、为什么是智能中控屏&#xff1f; 在智能音箱增…

诗一样的代码命名规范

有文化&#xff1a;落霞与孤鹜齐飞&#xff0c;秋水共长天一色&#xff1b;没文化&#xff1a;太阳落山的时候&#xff0c;看见一只鸟在水上飞&#xff1b;日常编码中&#xff0c;代码的命名是个大的学问。能快速的看懂开源软件的代码结构和意图&#xff0c;也是一项必备的能力…

Docker入门建议收藏 第二部分

二、Docker 容器技术与虚拟机的区别 Docker 到底是个什么东西呢&#xff1f;我们在理解 Docker 之前&#xff0c;首先得先区分清楚两个概念&#xff0c;容器和虚拟机。 虚拟机 虚拟机&#xff08;Virtual Machine&#xff09;指通过软件模拟的具有完整硬件系统功能的、运行在…

单链表的头插,尾插,头删,尾删等操作

前言顺序表要求是具有连续的物理空间&#xff0c;并且数据的话是在这些空间当中是连续的存储。但这样会带来很多问题&#xff0c;比如说在头部或者说中间插入的话&#xff0c;效率不是很高&#xff1b;并且申请空间可能需要扩容&#xff0c;并且越往后一般来说都是异地扩容&…