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`
  * 串行流下不需要合并容器
  * 并行流如果用的是并发容器,也不需要合并
相关推荐
雨中飘荡的记忆1 小时前
大流量下库存扣减的数据库瓶颈:Redis分片缓存解决方案
java·redis·后端
心之语歌4 小时前
基于注解+拦截器的API动态路由实现方案
java·后端
华仔啊5 小时前
Stream 代码越写越难看?JDFrame 让 Java 逻辑回归优雅
java·后端
ray_liang5 小时前
用六边形架构与整洁架构对比是伪命题?
java·架构
Ray Liang6 小时前
用六边形架构与整洁架构对比是伪命题?
java·python·c#·架构设计
Java水解7 小时前
Java 中间件:Dubbo 服务降级(Mock 机制)
java·后端
SimonKing11 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean11 小时前
Jackson View Extension Spring Boot Starter
java·后端
Seven9712 小时前
剑指offer-79、最⻓不含重复字符的⼦字符串
java
皮皮林55121 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java