• Stream流详解


    当我们对一个集合中的元素进行多次过滤应该怎样做?

    下面看一个案例

    • 按照下面的要求完成集合的创建和遍历

      • 创建一个集合,存储多个字符串元素

      • 把集合中所有以"张"开头的元素存储到一个新的集合

      • 把"张"开头的集合中的长度为3的元素存储到一个新的集合

      • 遍历上一步得到的集合

    • 原始方式示例代码

    1. public class MyStream1 {
    2. public static void main(String[] args) {
    3. //集合的批量添加
    4. ArrayList list1 = new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));
    5. //list.add()
    6. //遍历list1把以张开头的元素添加到list2中。
    7. ArrayList list2 = new ArrayList<>();
    8. for (String s : list1) {
    9. if(s.startsWith("张")){
    10. list2.add(s);
    11. }
    12. }
    13. //遍历list2集合,把其中长度为3的元素,再添加到list3中。
    14. ArrayList list3 = new ArrayList<>();
    15. for (String s : list2) {
    16. if(s.length() == 3){
    17. list3.add(s);
    18. }
    19. }
    20. for (String s : list3) {
    21. System.out.println(s);
    22. }
    23. }
    24. }
    1. public class test1 {
    2. public static void main(String[] args) {
    3. //集合的批量添加
    4. ArrayList list1 = new ArrayList<>(List.of("张三丰", "张无忌", "张翠山", "王二麻子", "张良", "谢广坤"));
    5. //Stream流
    6. list1.stream().filter(s -> s.startsWith("张")).filter(s -> s.length() == 3).forEach(s -> System.out.println(s));
    7. }
    8. }

    由此可见

    Java Stream流的好处体现在以下几个方面:

    1. 简化代码:Stream API允许开发者通过声明性方式处理数据,这意味着可以通过更少的代码实现相同的功能,从而提高代码的简洁性和可读性。
    2. 提高可维护性:由于Stream流的代码更加简洁,因此也更容易维护。当业务逻辑复杂时,使用Stream可以减少出错的机会,并且使得代码更加清晰。
    3. 函数式编程:Stream流基于函数式编程的思想,这使得它能够很好地支持抽象思维和函数式操作,有助于解决复杂的业务逻辑问题。
    4. 性能优化:Stream API设计时就考虑到了性能因素,它在内部进行了优化,比如延迟执行和短路操作等,可以在不修改代码的情况下享受性能提升的好处。
    5. 避免显式数据存储:Stream流不是一种数据结构,它不需要显式地存储数据,而是对数据进行加工和处理,这有助于减少内存的使用。
    6. 流水线操作:Stream流的处理方式类似于工厂的生产线,每个操作都是流水线上的一个工序,这样的设计使得数据处理流程更加清晰和高效。
    7. 避免手动管理线程:在使用Stream进行并行处理时,开发者不需要手动管理线程,Stream API会负责这部分工作,这样可以更加专注于业务逻辑本身。
    8. 易于并行化:Stream流可以很容易地将顺序流转换为并行流,从而利用多核处理器的优势,提高数据处理的速度。
    9. 强大的操作:Stream API提供了丰富的操作,如过滤、映射、排序等,这些操作可以组合起来形成强大的数据处理链。
    10. 灵活的数据源:Stream流不仅可以从集合创建,还可以从数组、I/O通道等多种数据源创建,这为数据处理提供了极大的灵活性。

    总的来说,Java Stream流通过提供一种高效、简洁、易于维护的方式来处理数据,极大地提升了开发效率和程序的性能。

    Stream流的三类方法

    • 获取Stream流

      • 创建一条流水线,并把数据放到流水线上准备进行操作

    • 中间方法

      • 流水线上的操作

      • 一次操作完毕之后,还可以继续进行其他操作

    • 终结方法

      • 一个Stream流只能有一个终结方法

      • 是流水线上的最后一个操作

      • 生成Stream流的方式

        • Collection体系集合

          使用默认方法stream()生成流, default Stream stream()

          1. public class test5 {
          2. public static void main(String[] args) {
          3. int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
          4. //获取stream流
          5. Arrays.stream(arr).forEach(s -> System.out.println(s));
          6. }
          7. }
        • Map体系集合

          把Map转成Set集合,间接的生成流

          1. public class test3 {
          2. public static void main(String[] args) {
          3. //双列集合
          4. //1.创建双列集合
          5. HashMap hm = new HashMap<>();
          6. //添加数据
          7. hm.put("aaa",111);
          8. hm.put("bbb",111);
          9. hm.put("ccc",111);
          10. hm.put("ddd",111);
          11. //3.第一种获取Stream流
          12. hm.keySet().stream().forEach(s -> System.out.println(s));
          13. //3.第二种获取Stream流
          14. hm.entrySet().stream().forEach(s -> System.out.println(s));
          15. }
          16. }

        • 数组

          通过Arrays中的静态方法stream生成流

          1. public class test2 {
          2. public static void main(String[] args) {
          3. //单列集合获取Stream流
          4. ArrayList list = new ArrayList<>();
          5. Collections.addAll(list,"a","b","c","d");
          6. list.stream().forEach(s -> System.out.println(s));
          7. }
          8. }
        • 同种数据类型的多个数据

          通过Stream接口的静态方法of(T... values)生成流

          1. public class test4 {
          2. public static void main(String[] args) {
          3. Stream.of(1,2,3,4,5).forEach(s -> System.out.println(s));
          4. }
          5. }

    Stream流中间操作方法

    • 概念

    中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作

    • 常见方法

    方法名说明
    Stream filter(Predicate predicate)用于对流中的数据进行过滤
    Stream limit(long maxSize)返回此流中的元素组成的流,截取前指定参数个数的数据
    Stream skip(long n)跳过指定参数个数的数据,返回由该流的剩余元素组成的流
    static Stream concat(Stream a, Stream b)合并a和b两个流为一个流
    Stream distinct()返回由该流的不同元素(根据Object.equals(Object) )组成的流
    1. public class MyStream3 {
    2. public static void main(String[] args) {
    3. // Stream filter(Predicate predicate):过滤
    4. // Predicate接口中的方法 boolean test(T t):对给定的参数进行判断,返回一个布尔值
    5. ArrayList list = new ArrayList<>();
    6. list.add("张三丰");
    7. list.add("张无忌");
    8. list.add("张翠山");
    9. list.add("王二麻子");
    10. list.add("张良");
    11. list.add("谢广坤");
    12. //filter方法获取流中的 每一个数据.
    13. //而test方法中的s,就依次表示流中的每一个数据.
    14. //我们只要在test方法中对s进行判断就可以了.
    15. //如果判断的结果为true,则当前的数据留下
    16. //如果判断的结果为false,则当前数据就不要.
    17. // list.stream().filter(
    18. // new Predicate() {
    19. // @Override
    20. // public boolean test(String s) {
    21. // boolean result = s.startsWith("张");
    22. // return result;
    23. // }
    24. // }
    25. // ).forEach(s-> System.out.println(s));
    26. //因为Predicate接口中只有一个抽象方法test
    27. //所以我们可以使用lambda表达式来简化
    28. // list.stream().filter(
    29. // (String s)->{
    30. // boolean result = s.startsWith("张");
    31. // return result;
    32. // }
    33. // ).forEach(s-> System.out.println(s));
    34. list.stream().filter(s ->s.startsWith("张")).forEach(s-> System.out.println(s));
    35. }
    36. }

    limit&skip代码演示

    1. public class StreamDemo02 {
    2. public static void main(String[] args) {
    3. //创建一个集合,存储多个字符串元素
    4. ArrayList list = new ArrayList();
    5. list.add("林青霞");
    6. list.add("张曼玉");
    7. list.add("王祖贤");
    8. list.add("柳岩");
    9. list.add("张敏");
    10. list.add("张无忌");
    11. //需求1:取前3个数据在控制台输出
    12. list.stream().limit(3).forEach(s-> System.out.println(s));
    13. System.out.println("--------");
    14. //需求2:跳过3个元素,把剩下的元素在控制台输出
    15. list.stream().skip(3).forEach(s-> System.out.println(s));
    16. System.out.println("--------");
    17. //需求3:跳过2个元素,把剩下的元素中前2个在控制台输出
    18. list.stream().skip(2).limit(2).forEach(s-> System.out.println(s));
    19. }
    20. }

    concat&distinct代码演示

    1. public class StreamDemo03 {
    2. public static void main(String[] args) {
    3. //创建一个集合,存储多个字符串元素
    4. ArrayList list = new ArrayList();
    5. list.add("林青霞");
    6. list.add("张曼玉");
    7. list.add("王祖贤");
    8. list.add("柳岩");
    9. list.add("张敏");
    10. list.add("张无忌");
    11. //需求1:取前4个数据组成一个流
    12. Stream s1 = list.stream().limit(4);
    13. //需求2:跳过2个数据组成一个流
    14. Stream s2 = list.stream().skip(2);
    15. //需求3:合并需求1和需求2得到的流,并把结果在控制台输出
    16. // Stream.concat(s1,s2).forEach(s-> System.out.println(s));
    17. //需求4:合并需求1和需求2得到的流,并把结果在控制台输出,要求字符串元素不能重复
    18. Stream.concat(s1,s2).distinct().forEach(s-> System.out.println(s));
    19. }
    20. }
    1. public class test6 {
    2. public static void main(String[] args) {
    3. /*
    4. map 转换流中的数据类型
    5. 注意点1: 中间方法,返回新的Stream流,原来的Stream流只能使用一次,建议使用链式编程
    6. 注意点2: 修改Stream流中的数据,不会影响原来集合或者数组中的数据
    7. */
    8. ArrayList list = new ArrayList<>();
    9. Collections.addAll(list,"张三-15","李四-16");
    10. //需求: 只获取里面的年龄并进行打印
    11. //String -> int
    12. //第一个类型: 流中原来的数据类型
    13. //第二个类型: 要转成之后的数据
    14. list.stream().map(new Function() {
    15. @Override
    16. public Integer apply(String s) {
    17. String[] arr = s.split("-");
    18. String ageString = arr[1];
    19. int age = Integer.parseInt(ageString);
    20. return age;
    21. }
    22. }).forEach(s -> System.out.println(s));
    23. list.stream().map(s -> Integer.parseInt(s.split("-")[1])).forEach(s -> System.out.println(s));
    24. }
    25. }

    Stream流终结操作方法

    • 概念

      终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作

    • 常见方法

      方法名说明
      void forEach(Consumer action)对此流的每个元素执行操作
      long count()返回此流中的元素数

    Stream流的收集操作

    • 概念

      对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中

    • 常用方法

      方法名说明
      R collect(Collector collector)把结果收集到集合中
    • 工具类Collectors提供了具体的收集方式

    方法名说明
    public static Collector toList()把元素收集到List集合中
    public static Collector toSet()把元素收集到Set集合中
    public static Collector toMap(Function keyMapper,Function valueMapper)把元素收集到Map集合中
    1. public class StreamTest5 {
    2. // toList和toSet方法演示
    3. public static void main(String[] args) {
    4. ArrayList list1 = new ArrayList<>();
    5. for (int i = 1; i <= 10; i++) {
    6. list1.add(i);
    7. }
    8. list1.add(10);
    9. list1.add(10);
    10. list1.add(10);
    11. list1.add(10);
    12. list1.add(10);
    13. //filter负责过滤数据的.
    14. //collect负责收集数据.
    15. //获取流中剩余的数据,但是他不负责创建容器,也不负责把数据添加到容器中.
    16. //Collectors.toList() : 在底层会创建一个List集合.并把所有的数据添加到List集合中.
    17. List list = list1.stream().filter(number -> number % 2 == 0).collect(Collectors.toList());
    18. System.out.println(list);
    19. Set set = list1.stream().filter(number -> number % 2 == 0)
    20. .collect(Collectors.toSet());
    21. System.out.println(set);
    22. }
    23. }
    1. public class StreamTest6 {
    2. public static void main(String[] args) {
    3. /*
    4. Stream流的收集方法 toMap方法演示
    5. 创建一个ArrayList集合,并添加以下字符串。字符串中前面是姓名,后面是年龄
    6. "zhangsan,23"
    7. "lisi,24"
    8. "wangwu,25"
    9. 保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
    10. */
    11. ArrayList list = new ArrayList<>();
    12. list.add("zhangsan,23");
    13. list.add("lisi,24");
    14. list.add("wangwu,25");
    15. Map map = list.stream().filter(
    16. s -> {
    17. String[] split = s.split(",");
    18. int age = Integer.parseInt(split[1]);
    19. return age >= 24;
    20. }
    21. // collect方法只能获取到流中剩余的每一个数据.
    22. //在底层不能创建容器,也不能把数据添加到容器当中
    23. ).collect(Collectors.toMap(
    24. s -> s.split(",")[0],
    25. s -> Integer.parseInt(s.split(",")[1])));
    26. System.out.println(map);
    27. }
    28. }

    案例来源:

    //https://www.bilibili.com/video/BV17F411T7Ao/?spm_id_from=333.337.search-card.all.click

  • 相关阅读:
    Java中实现一维数组逆序交换的完整解决方案
    Spring Boot 配置 jar 包外面的 Properties 配置文件
    Java Double isInfinite()方法具有什么功能呢?
    【题解】2023 DTS算法竞赛集训 第1次
    【Unity基础】3.脚本控制物体运动&天空盒
    Linux账号和权限
    HTML表格学习
    LeetCode 59. 螺旋矩阵 II
    正则表达式
    第六章 Scala if..else与循环
  • 原文地址:https://blog.csdn.net/m0_59166601/article/details/136357984