1、介绍
目的:用于简化集合和数组操作的 API,结合了 Lambda 表达式
Stream 流思想的核心
- 先得到集合或者数组的 Stream 流(就是一根传送带)
- 把元素放上去
- 然后就用这个 Stream 流简化的 API 来方便的操作元素
| List<String> names = new ArrayList<>(); |
| Collections.addAll(names, "张无忌", "周芷若", "赵敏", "张强", "张三丰"); |
| |
| names.stream() |
| .filter(name -> name.startsWith("张")) |
| .filter(name -> name.length() == 3) |
| .forEach(System.out::println); |
Stream 流的三类方法
- 获取 Stream 流:创建一条流水线,并把数据放到流水线上准备进行操作
- 中间方法:流水线上的操作,一次操作完毕之后,还可以继续进行其他操作
- 终结方法:一个 Stream 流只能有一个终结方法,是流水线上的最后一个操作
2、获取 Stream 流
Stream 操作集合或者数组的第一步是先得到 Stream 流,然后才能使用流的功能
集合获取 Stream 流的方式:可以使用 Collection 接口中的默认方法 stream() 生成流
方法名 |
说明 |
default Stream<E> stream() |
获取当前集合对象的 Stream 流 |
| Map<String, Integer> map = new HashMap<>(); |
| |
| Set<String> keySet = map.keySet(); |
| Stream<String> keyStream = keySet.stream(); |
| |
| Collection<Integer> values = map.values(); |
| Stream<Integer> valuesStream = values.stream(); |
| |
| Set<Map.Entry<String, Integer>> entries = map.entrySet(); |
| Stream<Map.Entry<String, Integer>> entryStream = entries.stream(); |
数组获取 Stream 流的方式
方法名 |
说明 |
public static <T> Stream<T> stream(T[] array) |
获取当前数组的 Stream 流(Arrays 的 API) |
public static <T> Stream<T> of(T... values) |
获取当前数组 / 可变数据的 Stream 流(Stream 的 API) |
| String[] names = {"张三", "李四", "王五"}; |
| |
| Stream<String> stringStream = Arrays.stream(names); |
| |
| Stream<String> nameStream = Stream.of(names); |
3、中间方法
中间方法也称为非终结方法,调用完成后返回新的 Stream 流可以继续使用,支持链式编程
在 Stream 流中无法直接修改集合、数组中的数据
名称 |
说明 |
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) |
合并 a 和 b 两个流为一个流 |
Stream<T> filter(Predicate<? super T> predicate) |
用于对流中的数据进行过滤 |
<R> Stream<R> map(Function<? super T, ? extends R> mapper) |
对流中的每个元素进行加工(Function<元素类型, 加工后的类型>) |
Stream<T> limit(long maxSize) |
获取前几个元素 |
Stream<T> skip(long n) |
跳过前几个元素 |
Stream<T> distinct() |
去除流中重复的元素,依赖 hashCode 和 equals 方法 |
Stream<T> sorted(Comparator<? super T> comparator) |
根据比较器规则对流中元素进行排序 |
| names.stream().map(new Function<String, String>() { |
| @Override |
| public String apply(String name) { |
| return "亲爱的".concat(name); |
| } |
| }).forEach(System.out::println); |
注意:中间方法会返回新的流,原来的流就不能用了,流只能使用一次
| Stream<String> stringStream = names.stream(); |
| |
| stringStream.filter(name -> name.startsWith("张")); |
| |
| stringStream.forEach(System.out::println); |
| |
一眼看穿 map 和 flatMap 的区别
| public class Map_FlatMap { |
| |
| List<String[]> eggs = new ArrayList<>(); |
| |
| @Before |
| public void init() { |
| |
| eggs.add(new String[]{"鸡蛋_1", "鸡蛋_1", "鸡蛋_1", "鸡蛋_1", "鸡蛋_1"}); |
| |
| eggs.add(new String[]{"鸡蛋_2", "鸡蛋_2", "鸡蛋_2", "鸡蛋_2", "鸡蛋_2"}); |
| } |
| |
| |
| static int group = 1; |
| |
| static int student = 1; |
| |
| |
| |
| |
| @Test |
| public void map() { |
| eggs.stream() |
| .map(x -> Arrays.stream(x).map(y -> y.replace("鸡", "煎"))) |
| .forEach(x -> System.out.println("组" + group++ + ":" + Arrays.toString(x.toArray()))); |
| |
| |
| |
| |
| |
| } |
| |
| |
| |
| |
| @Test |
| public void flatMap() { |
| eggs.stream() |
| .flatMap(x -> Arrays.stream(x).map(y -> y.replace("鸡", "煎"))) |
| .forEach(x -> System.out.println("学生" + student++ + ":" + x)); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| } |
| } |
4、终结方法
终结操作方法,调用完成后流就无法继续使用了,原因是不会返回 Stream 了
名称 |
说明 |
void forEach(Consumer<? super T> action) |
对此流的每个元素执行遍历操作 |
long count() |
返回此流中的元素数 |
Optional<T> max(Comparator<? super T> comparator) |
根据比较器规则获取流中元素的最大值 |
public T get() |
获取元素(Optional 的 API) |
5、收集 Stream 流
就是把 Stream 流操作后的结果数据恢复到集合或者数组中去
Stream 流:方便操作集合 / 数组的手段
集合 / 数组:才是开发中的目的
名称 |
说明 |
R collect(Collector collector) |
开始收集 Stream 流,指定收集器(集合) |
Object[] toArray() |
开始收集 Stream 流,结果为 Object 数组 |
<A> A[] toArray(IntFunction<A[]> generator) |
开始收集 Stream 流,结果为指定类型数组 |
Collectors 工具类提供了具体的收集方式
方法名 |
说明 |
public static <T> Collector toList() |
把元素收集到 List 集合中 |
public static <T> Collector toSet() |
把元素收集到 Set 集合中 |
public static Collector toMap(Function keyMapper, Function valueMapper) |
把元素收集到 Map 集合中 |
| Object[] objects = names.stream().toArray(); |
| |
| String[] strings = names.stream().toArray(new IntFunction<String[]>() { |
| @Override |
| public String[] apply(int length) { |
| return new String[length]; |
| } |
| }); |
| |
| |
| List<String> result = names.stream().filter(name -> name.length() == 3).collect(Collectors.toList()); |
| System.out.println(result); |
| |
| |
| List<UserInfo> userInfoList = userService.batchGetUserInfoByUserIds(userIdList); |
| Map<Long, UserInfo> userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserInfo::getUserId, userInfo -> userInfo)); |
6、加工演示
| |
| public class Student { |
| private String name; |
| } |
| |
| List<String> names = new ArrayList<>(); |
| Collections.addAll(names, "张无忌", "周芷若", "赵敏", "张强", "张三丰"); |
| |
| names.stream().map(new Function<String, Student>() { |
| @Override |
| public Student apply(String name) { |
| return new Student(name); |
| } |
| }).forEach(student -> students.add(student)); |
| |
| |
| |
| |
| List<Student> studentList = names.stream().map(Student::new).collect(Collectors.toList()); |
| System.out.println(studentList); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步