Java Stream流
参考资料: Java入门到飞起
1. 引言
随着Java版本的不断演进,Java 8引入了Stream流,Stream流是一种用于处理集合数据的抽象概念,它允许开发者以声明式的方式处理数据,就像流水线上的工序一样,将各种操作串联起来完成复杂的数据转换和处理任务。而方法引用则进一步简化了Lambda表达式的使用,使得代码更加简洁明了。
本文将深入探讨Java Stream流和方法引用的核心概念、使用场景和最佳实践。我们将从基础概念入手,逐步讲解Stream流的创建方式、中间操作和终结操作。
2. Stream流
2.1 体验Stream流
案例需求
按照以下要求完成集合的创建和遍历:
- 创建一个集合,存储多个字符串元素
- 把集合中所有以"张"开头的元素存储到一个新的集合
- 把"张"开头的集合中的长度为3的元素存储到一个新的集合
- 遍历上一步得到的集合
原始方式实现
jdk1.8使用List.of()会报错的,9版本以上是可以用;8版本的话,可以用add一点点加。
public class MyStream1 {public static void main(String[] args) {// 集合初始化ArrayList<String> list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));// 筛选以"张"开头的元素ArrayList<String> list2 = new ArrayList<>();for (String s : list1) {if(s.startsWith("张")){list2.add(s);}}// 筛选长度为3的元素ArrayList<String> list3 = new ArrayList<>();for (String s : list2) {if(s.length() == 3){list3.add(s);}}// 遍历输出for (String s : list3) {System.out.println(s);} }
}
Stream流实现
import java.util.ArrayList;
public class MyStream1 {public static void main(String[] args) {// 集合初始化ArrayList<String> list1 = new ArrayList<>();list1.add("张三丰");list1.add("张无忌");list1.add("张翠山");list1.add("王二麻子");list1.add("张良");list1.add("谢广坤");// 使用 Stream API 筛选并输出结果list1.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(System.out::println);}
}
Stream流优势
- 代码简洁:一行代码完成传统方式多行才能完成的操作
- 可读性强:方法链直观表达数据处理流程
- 函数式编程:引入Java的函数式编程范式
2.2 Stream流的常见生成方式
Stream流思想
Stream流可以看作数据的"流水线",数据从源头进入,经过一系列处理,最终被消费。
生成方式
集合类型 | 生成方式 | 示例 |
---|---|---|
Collection | stream() 方法 | list.stream() |
Map | 转换为Set后获取流 | map.keySet().stream() |
数组 | Arrays.stream() | Arrays.stream(arr) |
多个数据 | Stream.of() | Stream.of(1,2,3) |
代码示例
public class StreamDemo {public static void main(String[] args) {// Collection生成流List<String> list = new ArrayList<>();Stream<String> listStream = list.stream();// Map生成流Map<String,Integer> map = new HashMap<>();Stream<String> keyStream = map.keySet().stream();// 数组生成流String[] strArray = {"a", "b", "c"};Stream<String> arrayStream = Arrays.stream(strArray);// 多个数据生成流Stream<String> ofStream = Stream.of("x", "y", "z");}
}
2.3 Stream流中间操作方法
中间操作特点
- 返回新的Stream对象
- 可以链式调用多个中间操作
- 不立即执行,形成流水线
方法 | 说明 | 示例 |
---|---|---|
filter() | 过滤元素 | .filter(s -> s.startsWith("张")) |
limit() | 限制数量 | .limit(3) |
skip() | 跳过元素 | .skip(2) |
concat() | 合并流 | Stream.concat(s1, s2) |
distinct() | 去重 | .distinct() |
代码示例
package stream;import java.util.ArrayList;
import java.util.stream.Stream;/*** 该类演示了如何使用 Stream 流对集合进行过滤、限制和跳过操作。*/
public class StreamDemo {public static void main(String[] args) {ArrayList<String> names = new ArrayList<String>();names.add("林青霞");names.add("张曼玉");names.add("王祖贤");names.add("柳岩");names.add("张敏");names.add("张无忌");// 过滤以"张"开头的名字System.out.println("1.过滤姓张的人--------");names.stream().filter(s -> s.startsWith("张")).forEach(System.out::println);System.out.println("--------");// 限制前3个元素System.out.println("2.限制前三个元素--------");names.stream().limit(3).forEach(System.out::println);System.out.println("--------"); // 跳过前2个元素System.out.println("3.跳过第二个元素--------");names.stream().skip(2).forEach(System.out::println);System.out.println("--------");// 合并两个流并去重System.out.println("4. 合并2,3并去重--------");Stream<String> s1 = names.stream().limit(3);Stream<String> s2 = names.stream().skip(2);Stream.concat(s1, s2).distinct().forEach(System.out::println);}
}
结果输出:
1.过滤姓张的人--------
张曼玉
张敏
张无忌
--------
2.限制前三个元素--------
林青霞
张曼玉
王祖贤
--------
3.跳过第二个元素--------
王祖贤
柳岩
张敏
张无忌
--------
4. 合并2,3并去重--------
林青霞
张曼玉
王祖贤
柳岩
张敏
张无忌
PS E:\Trae\Traeproject>
2.4 Stream流终结操作方法
终结操作特点
- 执行后会关闭流,不能继续使用
- 通常用于获取结果或执行副作用操作
方法 | 说明 | 示例 |
---|---|---|
forEach() | 遍历元素 | .forEach(System.out::println) |
count() | 计数 | .count() |
代码示例
public class StreamDemo {public static void main(String[] args) {List<String> names = List.of("张三丰", "张无忌", "张翠山");// 遍历元素names.stream().forEach(System.out::println);// 计数long count = names.stream().filter(s -> s.startsWith("张")).count();System.out.println("以张开头的人数: " + count);}
}
2.5 Stream流的收集操作【应用】
收集操作
将Stream中的元素收集到集合或其他数据结构中
方法 | 说明 | 示例 |
---|---|---|
toList() | 收集到List | .collect(Collectors.toList()) |
toSet() | 收集到Set | .collect(Collectors.toSet()) |
toMap() | 收集到Map | .collect(Collectors.toMap(...)) |
代码示例
public class StreamDemo {public static void main(String[] args) {List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 收集到ListList<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());// 收集到SetSet<Integer> oddNumbers = numbers.stream().filter(n -> n % 2 != 0).collect(Collectors.toSet());// 收集到MapList<String> personList = List.of("张三,25", "李四,30", "王五,28");Map<String, Integer> personMap = personList.stream().filter(s -> {String[] parts = s.split(",");return Integer.parseInt(parts[1]) >= 25;}).collect(Collectors.toMap(s -> s.split(",")[0],s -> Integer.parseInt(s.split(",")[1])));}
}
2.6 Stream流综合练习
案例需求
处理演员数据:
- 男演员:名字为3个字的前三人
- 女演员:姓林的,并且不要第一个
- 合并结果创建Actor对象
代码实现
// Actor类
public class Actor {private String name;public Actor(String name) {this.name = name;}// getter/setter...@Overridepublic String toString() {return "Actor{name='" + name + "'}";}
}// 测试类
public class StreamTest {public static void main(String[] args) {ArrayList<String> manList = List.of("周润发", "成龙", "刘德华", "吴京", "周星驰", "李连杰");ArrayList<String> womanList = List.of("林心如", "张曼玉", "林青霞", "柳岩", "林志玲", "王祖贤");// 处理男演员Stream<String> manStream = manList.stream().filter(s -> s.length() == 3).limit(3);// 处理女演员Stream<String> womanStream = womanList.stream().filter(s -> s.startsWith("林")).skip(1);// 合并并创建Actor对象Stream.concat(manStream, womanStream).map(Actor::new) // 方法引用创建Actor.forEach(System.out::println); // 方法引用打印}
}
结果输出:
Actor:{name='周润发'}
Actor:{name='刘德华'}
Actor:{name='周星驰'}
Actor:{name='林青霞'}
Actor:{name='林志玲'}