Java Stream流与使用操作指南

2025-09-18 17:50
文章标签 java 使用 操作 指南 stream

本文主要是介绍Java Stream流与使用操作指南,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《JavaStream流与使用操作指南》Stream不是数据结构,而是一种高级的数据处理工具,允许你以声明式的方式处理数据集合,类似于SQL语句操作数据库,本文给大家介绍JavaStream流与使用...

一、什么是stream流

Java 8引入的Stream API是处理集合数据的一种全新方式,它代表了对数据元素序列进行函数式操作的抽象。Stream不是数据结构,而是一种高级的数据处理工具,允许你以声明式的方式处理数据集合,类似于SQL语句操作数据库

Stream的核心特点:

  • 声明式编程:只需说明"做什么"而非"如何做",代码更简洁易读
  • 函数式风格:与Lambda表达式完美结合,操作更灵活
  • 管道操作:多个操作可以连接起来形成数据处理流水线
  • 内部迭代:不同于集合的外部迭代(使用for-each),Stream在内部处理迭代过程
  • 延迟执行:中间操作不会立即执行,只有遇到终结操作才会触发计算
  • 不可复用:一个Stream只能被消费一次

二、创建stream流

1.单列集合创建stream流

      // 1.单列集合创建stream流
        List<String> list = Arrays.asList("张三", "李四", "王五", "赵六", "钱七");
        list.stream().forEach(e -> System.out.println("e = " + e));

2.双列集合创建stream流

        // 2.双列集合创建stream流
        HashMap<String, Integer> map = new HashMap<>();
        map.put("aaa", 111);
        map.put("bbb", 222);
        map.put("ccc", 333);
        map.put("ddd", 444);
        map.put("eee", 555);
        // 遍历所有的key
        map.keySet().stream().forEach(e -> System.out.println("e = " + e));
        // 遍历所有的键值对
        map.entrySet().stream().forEach(e -> System.out.println("e = " + e));
        // 遍历所有的值
        map.values().stream().forEach(e -> System.out.println("e = " + e));

3.数组创建stream流

        // 3.数组创建stream流
        int[] array1 = {1, 2, 3};
        String[] array2 = {"a", "b", "c"};
        Arrays.stream(array1).forEach(e -> System.out.println("e = " + e));

4.零散数据创建stream流

     // 4.零散数据创建stream流
        Stream.of(1, 2, 3, 4, 5).forEach(e -> System.out.println("e = " + e));
        // stream接口中静态方法of的细节
        // 方法的形参是一个可变参数,可以传递一堆零散的数据(同一类型),也可以传递数组
        // 传递的数组必须是引用数据类型的,如果传递基本数据类型,会把数组当做一个元素
        Stream.of(array1).forEach(e -> System.out.println("e = " + e));  // 结果[I@4dd8dc3
        Stream.of(array2).forEach(e -> System.out.println("e = " + e));

5.创建并行流

     // 5.创建并行流
        list.parallelStream().forEach(e -> System.out.println("e = " + e)); // 顺序会打乱

6.创建无限流

     // 6.创建无限流
        Stream.generate(Math::random).limit(10).forEach(e -> System.out.println("e = " + e));
        Stream.iterate(0, n -> n + 2).limit(10).forEach(e -> System.out.println("e = " + e));

三、流的中间操作

中间操作返回一个新的Stream,可以链式调用多个中间操作。

注意点:

一、中间方法,返回新的stream流,原来的stream流只能使用一次,建议使用链式编程

二、修改stream流中的数据,不会影响原来集合或数组中的数据

1.过滤操作

       // 1.过滤操作
        // filter: 过滤元素
        List<Integer> list1 = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 100, 100);
        List<Integer> list2 = Arrays.asList(100, 200, 30, 40, 50, 60, 70, 80, 90, 100, 200, 1000, 100000);
        list1.stream().filter(n -> n % 2 == 0).forEach(e -> System.out.println("e = " + e));
        // distinct: 去重
        // 依赖于hashCode和equals方法,底层使用的是hashset
        list1.stream().distinct().forEach(e -> System.out.println("e = " + e));

2.映射操作

     // 2.映射操作
        List<String> list3 = Arrays.asList("张三-13", "李四-14", "王五-15", "赵六-16", "钱七-17");
        list3.stream().map(s -> Integer.valueOf(s.split("-")[1])).forEach(e -> System.out.println("map = " + e));
         List<List<Integer>> numberLists = Arrays.asList(
                Arrays.asList(1, 2),
                Arrays.asList(3, 4, 5),
                Arrays.asList(6)
        );
        // flatMap 可以处理嵌套集合或需要"展平"数据结构的情况,将每个元素转换为一个流(Stream),然后把所有流合并成一个流
        // 当你需要处理嵌套结构或一对多转换时,使用flatMap;当只是简单的一对一转换时,使用map
        numberLists.stream().map(s -> s.stream()).forEach(stream -> System.out.println("stream = " + stream));  // 输出3个流对象的地址值 java.util.stream.ReferencePipeline$Head@3b9a45b3
        numberLists.stream().flatMap(s -> s.stream()).forEach(s -> System.out.println("flatMap = " + s)); // 输出 1 2 3 4 5 6

3.截取/跳过操作

      // 3.截取/跳过操作
        // limit: 限制元素数量
        list1.stream().limit(4).forEach(e -> System.out.println("e = " + e));
        // skip: 跳过前N个元素
        list1.stream().skip(5).forEach(e -> System.out.println("e = " + e));

4.排序操作

      // 4.排序操作
        // sorted: 排序
        Stream.of("b", "a", "c").sorted().forEach(s -> System.out.println("sorted = " + s));
        // 自定义排序
        Stream.of("aaa", "bb", "c").sorted(Comparator.comparingInt(String::length)).forEach(s -> System.out.println("customSorted  = " + s));
        Stream.of("aaa", "bb", "c", null).sorted((a, b) -> {
            if (a == null && b == null) return 0;
            if (a == null) return 1;
            if (b == null) return -1;
            return b.compareTo(a);
        }).forEach(s -> System.out.println("customSorted2  = " + s));

5.合并操作  ​​​​​​

      // 5.合并操作
        Stream.concat(list1.stream(), list2.stream()).forEach(e -> System.out.println("e = " + e));

6.其他中间操作

此API可以很好的证明流“延迟执行”的特点,当无forEach()时,不会打印出中间元素,当有终结操作时,流才会执行。  ​​​​​​

      // 6.其他中间操作
        // peek: 查看流中元素,调试用
        Stream.of("one", "two", "three")
                .peek(e -> System.out.println("Original: " + e))
                .map(String::toUpperCase)
                .peek(e -> System.out.println("Mapped: " + e))
                .forEach(e-> System.out.println("peek = " + e));

四、 流的终结操作

终结操作会触发流的处理并返回结果

1.遍历操作 ​​​​​​

     // 1.遍历操作
        List<String> list = Arrays.asList("张三-13", "李四-14", "王五-15", "赵六-16", "钱七-17", "张三-23");
        // forEach: 遍历元素
        list.stream().forEach(e -> System.out.println("e = " + e));
        // forEachOrdered: 保证顺序的遍历
        list.parallelStream().forEachOrdered(e -> System.out.println("e = " + e));

2.收集操作  ​​​​​​

      // 2.收集操作
        // 收集到list集合
        List<String> nameList = list.stream().map(e -> e.split("-")[0]).collect(Collectors.toList());
        System.out.println("nameList = " + nameList);
        // 收集到set集合,会去重
        Set<String> nameSet = list.stream().map(e -> e.split("-")[0]).collect(Collectors.toSet());
        System.out.println("nameSet = " + nameSet);
        // 收集到map集合
        // 注意收集到map,键不能重复,重复会报 java.lang.IllegalStateException: Duplicate key 张三 (attempted merging values 13 and 23)
//        Map<String, Integer> map1 = list.stream().collect(Collectors.toMap(s -> s.split("-")[0], s -> Integer.valueOf(s.split("-")[1])));
//        System.out.println("map1 = " + map1);
        // 解决方案,传递第三个参数,如果键重复,使用前面的那么,以下的(a, b)代表的value,a为已经存在的,b为新加的
        Map<String, Integer> map2 = list.stream().collect(Collectors.toMap(s -> s.split("-")[0], s -> Integer.valueOf(s.split("-")[1]), (a, b) -> a));
        System.out.println("map2 = " + map2);
        // 收集为字符串
        String nameStr = list.stream().map(e -> e.split("-")[0]).collect(Collectors.joining("-"));
        System.out.println("nameStr = " + nameStr);   // 张三-李四-王五-赵六-钱七-张三

3.聚合操作  

     // 3.聚合操作
        // count: 计数
        long count = Stream.of("a", "b", "c").count();
        System.out编程.println("count = " + count); // 3
        // max/min: 最大最小值
        Optional<String> max = Stream.of("a", "bb", "ccc").max(Comparator.comparingInt(String::length));
        System.out.println("max = " + max.get());
        // reduce: 归约操作
        // 无初始值,当流为空,则为Optional.empty()
       China编程 Optional<Integer> sum = Stream.of(1, 2, 3).reduce(Integer::sum);
        System.out.println("sum = " + androidsum.get()); // ccc
        // 初始值为0,流为空则返回0,执行的操作为 0+1+2+3 = 6
        Integer sumWithIdentity = Stream.of(1, 2, 3).reduce(0, Integer::sum);
        System.out.println("sumWithIdentity = " + sumWithIdentity); // 6

4.匹配操作 ​​​​​

       // 4.匹配操作
        // anyMatch: 任意元素匹配(任意一个满足条件则为true)
        boolean hasEven = Stream.of(1, 2, 3).anyMatch(n -> n % 2 == 0);
        System.out.println("hasEven = " + hasEven); // true
        // allMatch: 所有元素匹配(所有元素都要满足条件)
        boolean allEven = Stream.of(2, 4, 6).allMatch(n -> n % 2 == 0);
        System.out.println("allEven = " + allEven); // true
        // noneMatch: 没有元素匹配(所有元素都不能满足条件)
        boolean noneNegative = Stream.of(1, 2, 3).noneMatch(n -> n < 0);
        System.out.println("noneNegative = " + noneNegative); // tTAzqIIyrue

5.查找操作  ​​​​​​

      // 5.查找操作
        // findFirst: 查找第一个元素
        Optional<String> first = Stream.of("a", "b", "c").findFirst();
        System.out.println("first = " + first.get()); // a
        // findAny: 查找任意元素(在并行流中效率更高)
        Optional<String> any = Stream.of("a", "b", "c").parallel().findAny();
        System.out.println("any = " + any.get()); // b

6.数组转换

        // 6.数组转换
        // toArray: 转换为数组
        String[] array = Stream.of("a", "b", "c").toArray(String[]::new);
        System.out.println("array = " + Arrays.toString(array))http://www.chinasem.cn; // [a, b, c]

7.分组

        // 7.分组
        // 可将一个对象集合按照里面的某个字段转换为map,如key为ID,value为对象
        List<String> words = Arrays.asList("apple", "banana", "orange", "pear", "grape");
        Map<Integer, List<String>> groupedByLength = words.stream()
                .collect(Collectors.groupingBy(String::length));
        System.out.println(groupedByLength);

到此这篇关于Java Stream流与使用操作指南的文章就介绍到这了,更多相关Java Stream流内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于Java Stream流与使用操作指南的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155935

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Java中Redisson 的原理深度解析

《Java中Redisson的原理深度解析》Redisson是一个高性能的Redis客户端,它通过将Redis数据结构映射为Java对象和分布式对象,实现了在Java应用中方便地使用Redis,本文... 目录前言一、核心设计理念二、核心架构与通信层1. 基于 Netty 的异步非阻塞通信2. 编解码器三、

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

一篇文章彻底搞懂macOS如何决定java环境

《一篇文章彻底搞懂macOS如何决定java环境》MacOS作为一个功能强大的操作系统,为开发者提供了丰富的开发工具和框架,下面:本文主要介绍macOS如何决定java环境的相关资料,文中通过代码... 目录方法一:使用 which命令方法二:使用 Java_home工具(Apple 官方推荐)那问题来了,

JDK21对虚拟线程的几种用法实践指南

《JDK21对虚拟线程的几种用法实践指南》虚拟线程是Java中的一种轻量级线程,由JVM管理,特别适合于I/O密集型任务,:本文主要介绍JDK21对虚拟线程的几种用法,文中通过代码介绍的非常详细,... 目录一、参考官方文档二、什么是虚拟线程三、几种用法1、Thread.ofVirtual().start(

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关