Stream API流学习总结

方法总览

图片来自网络

过滤-filter

假设有如下stream流

java 复制代码
record Fruit(String cname, String name, String category, String color) { }

Stream.of(
    new Fruit("草莓", "Strawberry", "浆果", "红色"),
    new Fruit("桑葚", "Mulberry", "浆果", "紫色"),
    new Fruit("杨梅", "Waxberry", "浆果", "红色"),
    new Fruit("核桃", "Walnut", "坚果", "棕色"),
    new Fruit("草莓", "Peanut", "坚果", "棕色"),
    new Fruit("蓝莓", "Blueberry", "浆果", "蓝色")
)

找出其中蓝色的浆果:

写法一:

java 复制代码
record Fruit(String cname, String name, String category, String color) { }

		Stream.of(
				new Fruit("草莓", "Strawberry", "浆果", "红色"),
				new Fruit("桑葚", "Mulberry", "浆果", "紫色"),
				new Fruit("杨梅", "Waxberry", "浆果", "红色"),
				new Fruit("核桃", "Walnut", "坚果", "棕色"),
				new Fruit("草莓", "Peanut", "坚果", "棕色"),
				new Fruit("蓝莓", "Blueberry", "浆果", "蓝色")
		).filter(f->f.category().equals("浆果")&&f.color().equals("蓝色"))
		 .forEach(System.out::println);

写法二:

java 复制代码
record Fruit(String cname, String name, String category, String color) {
		}

		Stream.of(
						new Fruit("草莓", "Strawberry", "浆果", "红色"),
						new Fruit("桑葚", "Mulberry", "浆果", "紫色"),
						new Fruit("杨梅", "Waxberry", "浆果", "红色"),
						new Fruit("核桃", "Walnut", "坚果", "棕色"),
						new Fruit("草莓", "Peanut", "坚果", "棕色"),
						new Fruit("蓝莓", "Blueberry", "浆果", "蓝色")
				).filter(f -> f.category().equals("浆果"))
				.filter(f -> f.color().equals("蓝色"))
				.forEach(System.out::println);
	}

映射-map

给所有的水果加上"酱"字:

java 复制代码
record Fruit(String cname, String name, String category, String color) {
		}

		Stream.of(
						new Fruit("草莓", "Strawberry", "浆果", "红色"),
						new Fruit("桑葚", "Mulberry", "浆果", "紫色"),
						new Fruit("杨梅", "Waxberry", "浆果", "红色"),
						new Fruit("核桃", "Walnut", "坚果", "棕色"),
						new Fruit("草莓", "Peanut", "坚果", "棕色"),
						new Fruit("蓝莓", "Blueberry", "浆果", "蓝色")
				)
				.map(f->f.cname()+"酱")
				.forEach(System.out::println);
	}

map相当于拿到每一个数据,然后执行箭头后面操作

打印结果如下:

降维-flatmap

java 复制代码
record Fruit(String cname, String name, String category, String color) {
		}
		Stream.of(
						List.of(
								new Fruit("草莓", "Strawberry", "浆果", "红色"),
								new Fruit("桑葚", "Mulberry", "浆果", "紫色"),
								new Fruit("杨梅", "Waxberry", "浆果", "红色"),
								new Fruit("蓝莓", "Blueberry", "浆果", "蓝色")
						),
						List.of(
								new Fruit("核桃", "Walnut", "坚果", "棕色"),
								new Fruit("草莓", "Peanut", "坚果", "棕色")
						)
				)
				.flatMap(list -> list.stream())
				.forEach(System.out::println);

相当于将两个集合里面的数据提取出来,组成一个新的流。

构建流

根据已有的数组构建流:

java 复制代码
Arrays.stream(array)

根据已有的 Collection 构建流(包括 List,Set 等):

java 复制代码
List.of("a","b","c").stream()

把一个对象变成流:

java 复制代码
Stream.of("d")

把多个对象变成流:

java 复制代码
Stream.of("x", "y")

废话不多数,关于构建流,直接看代码:

java 复制代码
//1.根据集合构建流
		//这里的stream()是Collection接口的一个方法,所有单列集合的所有实现类都可以转换成流
		//包括list,set等集合
		List.of(1, 2, 3).stream().forEach(System.out::println);

		//2.双列集合没有stream方法,但是我们可以将双列集合转换成单列集合,再调用stream方法
		Map.of("a", 1, "b", 2)
				.entrySet()//转换成键值对对象
				.stream()//此时map集合是set集合的形态,可以转为流了
				.forEach(System.out::println);//打印

		//3.根据数组构建流
		int[] array = {1, 2, 3};
		Arrays.stream(array)
				.forEach(System.out::println);

		//4.根据对象创建流
		Stream.of(1, 2, 3).forEach(System.out::println);

合并和截取

java 复制代码
//1.合并
		Stream<Integer> s1 = Stream.of(1, 2, 3);
		Stream<Integer> s2 = Stream.of(4, 5);

		Stream<Integer> concat = Stream.concat(s1, s2);
		//concat.forEach(System.out::println);

		//2.截取-直接给出截取位置
		//skip(long n) 跳过n个数据,保留剩下的数据
		//limit(long n) 保留n个数据,其他的舍弃
		//concat.skip(2).forEach(System.out::println);//打印3,4,5
		//concat.limit(2).forEach(System.out::println);//打印1,2

		//留下中间的3,4的写法
		//concat.skip(2).limit(2).forEach(System.out::println);

		//3.截取-根据条件确定截取位置
		//dropWhile 是 drop 流中元素,直到条件不成立,留下剩余元素
		//takeWhile 是 take 流中元素,直到条件不成立,舍弃剩余元素
		//concat.takeWhile(x -> x < 3).forEach(System.out::println);
		//concat.dropWhile(x -> x < 3).forEach(System.out::println);

生成流

生成从 0 ~ 9 的数字(含头不含尾)

java 复制代码
IntStream.range(0, 10)

或者

java 复制代码
IntStream.rangeClosed(0, 9)

如果想订制,可以用 iterate 方法,例如下面生成奇数序列

java 复制代码
IntStream.iterate(1, x -> x + 2)
  • 参数1 是初始值

  • 参数2 是一个特殊 Function,即参数类型与返回值相同,它会根据上一个元素 x 的值计算出当前元素

  • 需要用 limit 限制元素个数

也可以用 iterate 的重载方法

java 复制代码
IntStream.iterate(1, x -> x < 10, x -> x + 2)

iterate 的特点是根据上一个元素计算当前元素,如果不需要依赖上一个元素,可以改用 generate 方法

例如下面是生成 5 个随机 int

java 复制代码
Stream.generate(()-> ThreadLocalRandom.current().nextInt()).limit(5)

不过如果只是生成随机数的话,有更简单的办法

java 复制代码
ThreadLocalRandom.current().ints(5)

如果要指定上下限,例如下面是生成从 0~9 的100个随机数

java 复制代码
ThreadLocalRandom.current().ints(100, 0, 10)

查找和判断

下面的代码找到流中任意(Any)一个偶数:

java 复制代码
int[] array = {1, 3, 5, 4, 7, 6, 9};

Arrays.stream(array)
    .filter(x -> (x & 1) == 0)
    .findAny()
    .ifPresent(System.out::println);

查找的案例:

java 复制代码
		//1.findFirst() 返回符合要求的第一个值
		IntStream stream = IntStream.of(1, 2, 3, 4 5);
		//System.out.println(stream.filter(x -> (x & 1) == 0).findFirst().orElse(-1));
		//解释:.filter(x -> (x & 1) == 0)表示查找流里面是否有偶数
		//.findFirst()表示将符合要求的数据中返回第一个元素
		//.orElse(-1)表示如果没有符合要求的数据,则返回值-1
		stream.filter(x -> (x & 1) == 0).findFirst().ifPresent((x) ->        System.out.println(x));
		//.ifPresent((x) -> System.out.println(x)表示如果存在符合的数据,则打印出来


		//2.findAny找到任意一个元素即可(并行流中可以看出和findFirst的区别)
		stream.filter(x -> (x & 1) == 0).findAny().ifPresent((x) -> System.out.println(x));

判断的案例:

java 复制代码
		//1.findFirst() 返回符合要求的第一个值
		IntStream stream = IntStream.of(1, 2, 3, 4, 5);

		//System.out.println(stream.anyMatch(x -> (x & 1) == 0));//true
		//System.out.println(stream.allMatch(x -> (x & 1) == 0));//false
		System.out.println(stream.noneMatch(x -> (x & 1) == 0));//false

去重和排序

java 复制代码
		//去重
		//IntStream.of(1, 2, 3, 1, 2, 3, 4, 5)
		//		.distinct()
		//		.forEach(System.out::println);

		//排序
		record Hero(String name, int strength) {
		}

		Stream.of(
						new Hero("独孤求败", 100),
						new Hero("令狐冲", 90),
						new Hero("风清扬", 98),
						new Hero("东方不败", 98),
						new Hero("方证", 92),
						new Hero("任我行", 92),
						new Hero("冲虚", 90),
						new Hero("向问天", 88),
						new Hero("不戒", 88)
				)
				.sorted((a, b) -> a.strength() < b.strength() ? -1 : a.strength() == b.strength() ? 0 : 1)
				.forEach(System.out::println);

化简

reduce(init, (p,x) -> r)

  • init 代表初始值

  • (p,x) -> r 是一个 BinaryOperator,作用是根据上次化简结果 p 和当前元素 x,得到本次化简结果 r

这样两两化简,可以将流中的所有元素合并成一个结果

java 复制代码
record Hero(String name, int strength) {
		}

		Stream.of(
				new Hero("独孤求败", 100),
				new Hero("令狐冲", 90),
				new Hero("风清扬", 98),
				new Hero("东方不败", 98),
				new Hero("方证", 92),
				new Hero("任我行", 92),
				new Hero("冲虚", 90),
				new Hero("向问天", 88),
				new Hero("不戒", 88)
		).reduce((h1, h2) -> h1.strength() > h2.strength() ? h1 : h2);

收集

java 复制代码
collect( supplier, accumulator, combiner)

* supplier 是描述如何创建收集容器 c :`()-> c`
* accumulator 是描述如何向容器 c 添加元素 x:`(c, x) -> void`
* combiner 是描述如何合并两个容器:`(c1, c2) -> void`
  * 串行流下不需要合并容器
  * 并行流如果用的是并发容器,也不需要合并
相关推荐
不务专业的程序员--阿飞3 分钟前
JVM无法分配内存
java·jvm·spring boot
李昊哲小课7 分钟前
Maven 完整教程
java·maven
Lin_Aries_042116 分钟前
容器化简单的 Java 应用程序
java·linux·运维·开发语言·docker·容器·rpc
脑花儿23 分钟前
ABAP SMW0下载Excel模板并填充&&剪切板方式粘贴
java·前端·数据库
北风朝向1 小时前
Spring Boot参数校验8大坑与生产级避坑指南
java·spring boot·后端·spring
闭着眼睛学算法1 小时前
【华为OD机考正在更新】2025年双机位A卷真题【完全原创题解 | 详细考点分类 | 不断更新题目 | 六种主流语言Py+Java+Cpp+C+Js+Go】
java·c语言·javascript·c++·python·算法·华为od
山海不说话1 小时前
Java后端面经(八股——Redis)
java·开发语言·redis
哈哈很哈哈1 小时前
Flink SlotSharingGroup 机制详解
java·大数据·flink
真的想不出名儿1 小时前
springboot - 邮箱验证码登录
java·springboot·邮箱验证
the beard2 小时前
JVM垃圾回收器深度解析:从Serial到G1,探索垃圾回收的艺术
java·jvm