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`
  * 串行流下不需要合并容器
  * 并行流如果用的是并发容器,也不需要合并
相关推荐
桦说编程2 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
lifallen2 小时前
Java Stream sort算子实现:SortedOps
java·开发语言
IT毕设实战小研2 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
没有bug.的程序员3 小时前
JVM 总览与运行原理:深入Java虚拟机的核心引擎
java·jvm·python·虚拟机
甄超锋3 小时前
Java ArrayList的介绍及用法
java·windows·spring boot·python·spring·spring cloud·tomcat
阿华的代码王国3 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Zyy~3 小时前
《设计模式》装饰模式
java·设计模式
A尘埃4 小时前
企业级Java项目和大模型结合场景(智能客服系统:电商、金融、政务、企业)
java·金融·政务·智能客服系统
青云交4 小时前
Java 大视界 -- 基于 Java 的大数据可视化在城市交通拥堵治理与出行效率提升中的应用(398)
java·大数据·flink·大数据可视化·拥堵预测·城市交通治理·实时热力图
CHEN5_025 小时前
【Java基础面试题】Java基础概念
java·开发语言