java_stream流

stream 流

前言 :

为啥要学习Steam , Stream(流)是一种在编程中处理数据序列的概念。它提供了一种高效、便捷的方式来对数据进行操作和处理。

Stream 可以看作是一个元素序列,可以是数组、集合或输入/输出资源等。与传统的集合操作不同,Stream 并不是存储数据的容器,而是通过一系列的操作来处理数据并生成结果。

使用 Stream,我们可以进行各种数据操作,例如过滤、映射、排序、聚合等。这些操作可以按照链式的方式组合,形成一个操作流水线。每个操作都会在数据上进行处理,并将结果传递给我们

本文是基于 B站 Stream 流学习的笔记 相关学习视频

1. stream 流初体验


这里 创建一个集合元素 完成一下需求

  1. 把所有以 开头的元素存储到 新集合中
  2. 把所有 开头的 ,长度为 3 的元素 在 存储到新的集合中
  3. 遍历打印最终结果


按照以往 会这么写

package com.rabbitmq.springboot_rabbitmq.Test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

public class StreamTest {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌", "张三丰", "王五", "大古", "迪迦", "飞鸟信", "戴拿", "张小马仔");


        // 1. 把所有 张开头的 元素存储到 新的集合中
        ArrayList<String> list2 = new ArrayList<>();
        for (String name : list) {
            if (name.startsWith("张")) {
                list2.add(name);
            }
        }
        System.out.println(list2);

        System.out.println("----------------------------------------------");

        // 2.把所有 `张` 开头的 ,长度为 3 的元素 在 存储到新的集合中
        ArrayList<String> list3 = new ArrayList<>();
        for (String name : list2) {
            if (name.length() == 3) {
                list3.add(name);
            }
        }
        System.out.println(list3);

        System.out.println("----------------------------------------------");

        // 3. 遍历打印最终结果
        for (String name : list3) {
            System.out.println(name);
        }

    }
}

效果:

在这里插入图片描述


这里如果我们使用 stream 流 就只需要写一行代码就可以完成上面的 这么多代码.

public class StreamTest {


    public static void main(String[] args) {

        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌", "张三丰", "王五", "大古", "迪迦", "飞鸟信", "戴拿", "张小马仔");

        list.stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3).forEach(name -> System.out.println(name));

    }
}

在这里插入图片描述

这里是不是就非常的高效,代码非常的精简,下面我们就来开启对stream 流的学习.

2. 获取 Stream 流


这里先来简单看看 stream 流的使用步骤 :

  1. 获得一条 stream 流 (可以理解为是一条流水线) , 并把数据放上去
  2. 使用 中间方法 (调用后还能调用其他方法) 对流水线进行操作
  3. 使用 终结方法 (调用后就不能再调用其他方法了) 对流水线的数据进行操作.


有了步骤 ,就来学习如何获取到 stream 流


引用 :

在这里插入图片描述


这里的双列集合 就为 : map 等


代码演示 :

2.1 单列集合 获取 stream 流

在这里插入图片描述

package com.example.demo.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;
import java.util.stream.Stream;

public class StreamDome {
    public static void main(String[] args) {
        // 单列集合获取 Stream 流
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "a", "b", "c", "d", "e");
        // 获取到一条流水线 , 并把集合中的 数据放到流水线上
        Stream<String> stream = list.stream();
        // 使用 终结方法 打印一下流水线上的所有参数
//        stream.forEach(new Consumer<String>() {
//            @Override
//            public void accept(String s) {
//                // s: 依次表示流水线上的每个数据
//                System.out.println(s);
//            }
//        });
        stream.forEach(s -> System.out.println(s));
    }
}

2.2 双列集合 获取 Stream 流

注意: 双列集合是不能直接获取到 Stream 流的 需要先将双列集合转为单列集合才能获取

在这里插入图片描述


代码:

package com.example.demo.Test;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;

public class StreamDome2 {

    public static void main(String[] args) {
        // 1. 创建双列集合
        HashMap<String, Integer> hm = new HashMap<>();

        // 2. 添加数据
        hm.put("aaa", 11);
        hm.put("bbb", 22);
        hm.put("ccc", 33);
        hm.put("ddd", 44);
        hm.put("fff", 55);

        // 3. 获取 stream 流
        Stream<String> stream = hm.keySet().stream();

        stream.forEach(s -> System.out.println(s));

        Stream<Map.Entry<String, Integer>> stream2 = hm.entrySet().stream();

        stream2.forEach(s -> System.out.println(s));
    }
}

2.3 数组获取 stream 流


数组获取 stream 流 需要借助 Arrays 工具类的静态方法

在这里插入图片描述


代码:

package com.example.demo.Test;

import java.util.Arrays;

public class StreamDome3 {

    public static void main(String[] args) {
        // 1. 创建数组
        int[] arr = {1, 2, 4, 5, 6, 7, 8, 9, 10};

        // 2. 获取 stream 流
        Arrays.stream(arr).forEach(s -> System.out.println(s));

        System.out.println("------------------------------------");
        // 3. 引用类型 获取 stream 流
        String[] str = {"你好", "帅哥", "和", "美女", "点个赞"};

        // 链式法则 打印出 str 里面的数据
        Arrays.stream(str).forEach(s -> System.out.println(s));

        Arrays.s
    }
}

2.4 一堆零散数据获取 Stream 流


注意: 这一堆零散的数据需要是同一种数据类型 ,使用 Stream.of() 方法创建一个Stream 流


代码:

package com.example.demo.Test;

import java.util.stream.Stream;

public class StreamDome4 {

    public static void main(String[] args) {

        // 基础数据类型
        Stream.of(1, 2, 3, 4, 5, 6).forEach(s -> System.out.println(s));

        // 引用数据类型
        Stream.of("你好", "帅哥", "点赞").forEach(s -> System.out.println(s));
    }
}


效果:

在这里插入图片描述


小细节 : 这里 Stream.of() 创建的 Stream 可以对 引用类型的数组 创建

在这里插入图片描述

获取 Stream 流 看完,接下来来看看 有关于 Stream 的中间方法

3. Stream 流的中间方法


引用:

在这里插入图片描述


注意:

  1. 中间方法 , 返回 新的 Stream 流 ,原来的Stream 流只能使用一次 ,建议使用 链式编程
  2. 修改 Stream流中的 数据 , 不会影响原来集合或者数组中的数据

3.1 filter 过滤方法

图一:

在这里插入图片描述


图二:

在这里插入图片描述


代码:

package com.example.demo.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Predicate;
import java.util.stream.Stream;

public class StreamDome5 {
    public static void main(String[] args) {

        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌", "张三", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

        // 过滤规则 : 把张开头的留下来 , 其余的数据过滤不要

//        list.stream().filter(new Predicate<String>() {
//            @Override
//            public boolean test(String s) {
//                // 返回值为 true 表示当前数据留下 , 为 false 表示当前数据丢弃
//                if (s.startsWith("张")) {
//                    // startsWith 方法 判断 s 是否以 张开头 如果是 返回 true 否者返回 false
//                    return true;
//                }
//                return false;
//            }
//        }).forEach(s -> System.out.println(s));

//        list.stream().filter(s -> s.startsWith("张")).forEach(s -> System.out.println(s));

//        Stream<String> stream1 = list.stream().filter(s -> s.startsWith("张"));
//
//        Stream<String> stream2 = stream1.filter(s -> s.length() == 3);
//
//        stream2.forEach(s -> System.out.println(s));


//        Stream<String> stream3 =  stream1.filter(s -> s.length() == 3);


        list.stream().
                filter(s -> s.startsWith("张")).
                filter(s -> s.length() == 3).
                forEach(s -> System.out.println(s));

        System.out.println(list);
    }

}

3.2 limit 和 skip 方法

limit 方法 是用来获取 stream 流上前几个 元素的方法

skip 方法 是用来跳过 stream流 前指定元素个数的方法

代码:

package com.example.demo.Test;

import java.util.ArrayList;
import java.util.Collections;

public class StreamDome6 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌", "张三", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

        // 通过 limit(3) 获得前 三个元素
        list.stream().limit(3).forEach(s -> System.out.println(s));

        System.out.println("------------------------");

        // 通过 skip(4) 跳过前4 个 元素 , 打印 stream 流后面的元素
        list.stream().skip(4).forEach(s -> System.out.println(s));

    }
}

效果:

在这里插入图片描述


小练习

集合数据 : “张无忌”, “张三”, “赵敏”, “张强”, “张三丰”, “张翠山”, “张良”, “王二麻子”, “谢广坤”

这里想要打印出 张强 , 张三丰 , 张翠山 通过 limit 和 skip 方法 要如何做 才能 打印 .


答案 :

  1. 先通过 limit 获取到前6条数据 ,然后通过 skip 跳过前3 条数据即可
  2. 先通过 skip 跳过前3 条数据 ,然后通过 limit 获取 3 个数据


代码:

public class StreamDome6 {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌", "张三", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

        // 方法一: 
        list.stream().limit(6).skip(3).forEach(s -> System.out.println(s));

        System.out.println("-------------------------");

        // 方法二:
        list.stream().skip(3).limit(3).forEach(s -> System.out.println(s));
    }
}


效果:

在这里插入图片描述

3.3 distinct 去重方法


distinct 方法 实现元素曲中 是依赖 hashCode 和 equals 方法

public class StreamDome6 {


    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张三", "张三", "李四", "李四", "王五", "王五");

        list.stream().distinct().forEach(s -> System.out.println(s));

    }
}


效果: 可以看到通过 distinct 方法就将重复的数据去除了

在这里插入图片描述


这里 ArrayList 集合是已经实现好了 hashCode 和 equals 方法 所以能够 实现 元素去重 .

下面我们来简单的看看 distinct 方法是如何实现的 ,这里通过 ctrl + alt + b 快捷键 进入到 distinct 方法的实现类.

在这里插入图片描述

3.4 cancat 方法

cancat 方法 是用来将多个流合并成一个 流的方法


代码:

public class StreamDome6 {


    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌", "张三", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

        ArrayList<Object> list2 = new ArrayList<>();

        Collections.addAll(list2, "喜羊羊", "灰太狼");

        Stream.concat(list.stream(), list2.stream()).forEach(s -> System.out.println(s));
    }
}


效果:

在这里插入图片描述

两个流的数据就合并到一起并通过 forEach 打印出来了.

3.5 map 方法


map 方法是用来 转化 流中的数据类型

在这里插入图片描述


代码: 匿名内部类

public class StreamDome6 {


    public static void main(String[] args) {

        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌-20", "张三-14", "赵敏-100");

        // 需求: 只获取里面的年龄并进行打印 String --> int


        // 第一个参数类型: 流中原本的数据类型
        // 第二个参数类型: 要转成之后的类型

        list.stream().map(new Function<String, Integer>() {

            // apply 形参的 s: 依次表示流里面的每一个数据
            // 返回值: 表示转换之后的数据
            @Override
            public Integer apply(String s) {
                String[] arr = s.split("-");
                String ageString = arr[1];

                return Integer.parseInt(ageString);
            }

            // 当 map 方法执行完成后 , 流上的数据就变成了 整数
            // 所以 在下面的 forEach 当中 , s 依次表示流里面的每个数据就是一个整数
        }).forEach(s -> System.out.println(s));
    }
}


Lambda 表达式

public class StreamDome6 {


    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌-20", "张三-14", "赵敏-100");

        list.stream().map(s -> Integer.parseInt(s.split("-")[1])).forEach(s -> System.out.println(s));
    }
}

4. Stream 流的终结方法


引用 :

在这里插入图片描述

4.1 forEach 遍历方法


forEach 上面一直在使用 ,就是依次遍历 流里面的每个数据,下面简单演示一下 就去看下一个方法


图:

在这里插入图片描述


代码:

package com.example.demo.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.function.Consumer;

public class StreamDome7 {

    public static void main(String[] args) {

        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "张三", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

        // 获取 stream 流
        list.stream().forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });

        System.out.println("-----------");

        list.stream().forEach(s -> System.out.println(s));

    }
}

4.2 count 统计方法


count 方法 是用来统计 流里面数据的个数的 ,很简单 使用一边就会了.

在这里插入图片描述


代码:

public class StreamDome7 {


    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌", "张三", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

        System.out.println(list.size());
        System.out.println("-------------------");
        long number = list.stream().filter(s -> s.startsWith("张")).count();
        System.out.println(number);
    }
}

4.3 toArray 收集方法 (数组)

toArray 方法 是用来收集的 是将流里面的数据收集起来放到一个数组当中


图一:

在这里插入图片描述


图二:

在这里插入图片描述


代码:

public class StreamDome7 {

    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌", "张三", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

        String[] array = list.stream().toArray(value -> {
            return new String[value];
        });

        System.out.println(Arrays.toString(array));
    }

    public static void main5(String[] args) {

        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌", "张三", "赵敏", "张强", "张三丰", "张翠山", "张良", "王二麻子", "谢广坤");

        String[] array = list.stream().toArray(new IntFunction<String[]>() {
            @Override
            public String[] apply(int value) {
                return new String[value];
            }
        });
        System.out.println(Arrays.toString(array));

    }
}

4.4 Collect 收集方法 (集合)


Collect 方法是将 流上的数据 收集到 集合当中


图一:

在这里插入图片描述


图二:

在这里插入图片描述


代码:

public class StreamDome7 {


    // Lambda 表达式 收集到 map 集合
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌-男-15", "张三-男-25", "赵敏-女-18", "张强-男-45", "张三丰-男-15",
                "张翠山-男-15", "张良-男-58", "王二麻子-女-82", "谢广坤-女-68");

        Map<String, Integer> map = list.stream().collect(Collectors.toMap(
                s -> s.split("-")[0],
                s -> Integer.parseInt(s.split("-")[2])
        ));

        System.out.println(map);


    }

    // 收集到 Map 集合
    public static void main8(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌-男-15", "张三-男-25", "赵敏-女-18", "张强-男-45", "张三丰-男-15",
                "张翠山-男-15", "张良-男-58", "王二麻子-女-82", "谢广坤-女-68", "谢广坤-女-68", "谢广坤-女-68");

        Map<String, Integer> map = list.stream().filter(s -> "女".equals(s.split("-")[1])).
                collect(Collectors.toMap(
                        new Function<String, String>() {
                            @Override
                            public String apply(String s) {
                                String[] arr = s.split("-");
                                return arr[0];
                            }
                        },
                        new Function<String, Integer>() {
                            @Override
                            public Integer apply(String s) {
                                String[] arr = s.split("-");
                                return Integer.parseInt(arr[2]);
                            }
                        }
                ));

        System.out.println(map);

    }

    // 收集到 Set 集合
    public static void main7(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌-男-15", "张三-男-25", "赵敏-女-18", "张强-男-45", "张三丰-男-15",
                "张翠山-男-15", "张良-男-58", "王二麻子-女-82", "谢广坤-女-68", "谢广坤-女-68", "谢广坤-女-68");

        // 要求:
        // 将 性别为男的数据 收集 Set 集合当中

        Set<String> arr = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toSet());

        System.out.println(arr);
    }
    
    
    
	// 收集到 List 集合
    public static void main6(String[] args) {
        ArrayList<String> list = new ArrayList<>();

        Collections.addAll(list, "张无忌-男-15", "张三-男-25", "赵敏-女-18", "张强-男-45", "张三丰-男-15",
                "张翠山-男-15", "张良-男-58", "王二麻子-女-82", "谢广坤-女-68", "谢广坤-女-68", "谢广坤-女-68");

        // 要求:
        // 将 性别为男的数据 收集 List 集合当中

        List<String> arr = list.stream().filter(s -> "男".equals(s.split("-")[1])).collect(Collectors.toList());

        System.out.println(arr);
    }


}

到此 关于 stream 流的相关操作 就学习完成了下面来完成几个练习就结束本文的学习 .

5. Stream 流练习

5.1 数据过滤


题目一: 定义一个集合 , 并添加 一些整数 1,2,3,4,5,6,7,8,9,10 过滤偶数,只留下奇数 ,并将结果保存起来.


代码:

package com.example.demo.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collector;
import java.util.stream.Collectors;

public class StreamDemo8 {

    public static void main(String[] args) {
        ArrayList<Integer> arr = new ArrayList<>();

        Collections.addAll(arr, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        List<Integer> arr2 = arr.stream().filter(number -> number % 2 == 1).collect(Collectors.toList());

        System.out.println(arr2);
    }
}


效果:

在这里插入图片描述

题目二 : 创建一个 ArrayList 集合 并添加一下字符 ,字符串前面是姓名 ,后面是 年龄 zhangsan,23 , lisi,24 , wangwu,25 保留大于等于 24 岁的 人 并将结果收集到 map 集合中 , 姓名为键 , 年龄为值。

代码:

public class StreamDemo8 {


    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "zhangsan,23", "lisi,24", "wangwu,25");

        Map<String, String> map = list.stream().filter(s -> 23 < Integer.parseInt(s.split(",")[1])).collect(Collectors.toMap(
                s -> s.split(",")[0],
                s -> s.split(",")[1]
        ));

        System.out.println(map);
    }
}

效果:

在这里插入图片描述

5.2 自定义对象过滤并收集


题目:

现在有两个 ArrayList 集合 , 分别存储 6 名 男演员 的名字 和 年龄 以及 6 名 女演员的名字和年龄 .

姓名 和 年ing 使用逗号隔开 , 比如 : 张三,23

要求完成如下操作 :

  1. 男演员只要名字为 3 个字的前两人.
  2. 女演员只要姓杨的 , 并且不要第一个.
  3. 把过滤后的男演员姓名和女演员的姓名合并到一起
  4. 将上一步的演员姓名封装成 Actor 对象
  5. 将所有的演员都保存到 List 集合中

备注 : 演员类 Actor 属性有 : name , age

数据 :

男演员 : “菜坤坤 , 24” , “叶齁咸,23” , “刘不甜 , 22” , “吴签, 24” , “谷嘉,30” , “肖侯 , 27”

女演员 : “赵小颖,17”, “高圆圆,32”, “张天天,20”, “杨颖,20”,“刘亦菲,18”, “杨洋羊,20”

代码:

public class StreamDemo8 {


    static class Actor {
        private String name;
        private Integer age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getAge() {
            return age;
        }

        public void setAge(Integer age) {
            this.age = age;
        }

        @Override
        public String toString() {
            return "Actor{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }

        public Actor(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    }

    public static void main(String[] args) {

        // 创建集合
        ArrayList<String> manList = new ArrayList<>();
        ArrayList<String> wuManList = new ArrayList<>();
        // 添加数据
        Collections.addAll(manList, "菜坤坤,24", "叶齁咸,23", "刘不甜,22", "吴签,24", "谷嘉,30", "肖侯,27");
        Collections.addAll(wuManList, "赵小颖,17", "高圆圆,32", "张天天,20", "杨颖,20", "刘亦菲,18", "杨洋羊,20");


        // 1. 男演员只要名字为 3 个字的前两人.
        Stream<String> manStream = manList.stream().
                filter(s -> s.split(",")[0].length() == 3).
                limit(2);


        // 2. 女演员只要姓杨的 , 并且不要第一个.
        Stream<String> wuManStream = wuManList.stream().filter(s -> s.startsWith("杨")).skip(1);

        // 3. 把过滤后的男演员姓名和女演员的姓名合并到一起 (合并两个流)
//        Stream.concat(manStream, wuManStream).forEach(s -> System.out.println(s));

        // 4. 将上一步的演员姓名封装成 Actor 对象 (将 String 转化为 Actor )
        // 使用 map 方法 将 流里面的数据 进行类型转换

        // 使用匿名内部类
//        Stream.concat(manStream, wuManStream).map(new Function<String, Actor>() {
//            @Override
//            public Actor apply(String s) {
//                String[] arr = s.split(",");
//                String name = arr[0];
//                Integer age = Integer.parseInt(arr[1]);
//                Actor actor = new Actor();
//                actor.setName(name);
//                actor.setAge(age);
//                return actor;
//            }
//        }).forEach(s-> System.out.println(s));

        // 使用 Lambda
//        Stream.concat(manStream, wuManStream).
//                map(s -> {
//                    return new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1]));
//                })
//                .forEach(s -> System.out.println(s));

        // 5. 将所有的演员都保存到 List 集合中
        List<Actor> actors = Stream.concat(manStream, wuManStream).
                map(s -> {
                    return new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1]));
                })
                .collect(Collectors.toList());

        System.out.println(actors);


    }
   
}

到此 本文 就完了, 关于 stream 流 其实还有一些 方法 可以自行了解 .

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值