Java的Stream流

感受 Stream 流的作用

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

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

ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
  1. 把所有以“张”开头的元素存储到新集合中
  2. 把“张”开头的,长度为3的元素再存储到新集合中
  3. 遍历打印最终结果
package com.faxont.stream;

import java.util.ArrayList;

public class StreamDemo1 {
    public static void main(String[] args) {
        /*
            创建集合添加元素,完成以下需求:
            1. 把所有以“张”开头的元素存储到新集合中
            2. 把“张”开头的,长度为3的元素再存储到新集合中
            3. 遍历打印最终结果
         */
        ArrayList<String> list = new ArrayList<>();
        list.add("张无忌");
        list.add("周芷若");
        list.add("赵敏");
        list.add("张强");
        list.add("张三丰");

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

//        // 1. 把所有以“张”开头的元素存储到新集合中
//        ArrayList<String> list2 = new ArrayList<>();
//        for (String name : list) {
//            if(name.startsWith("张")){
//                list2.add(name);
//            }
//        }
//
//        // 2. 把“张”开头的,长度为3的元素再存储到新集合中
//        ArrayList<String> list3 = new ArrayList<>();
//        for (String name : list2) {
//            if(name.length() == 3){
//                list3.add(name);
//            }
//        }
//
//        // 3. 遍历打印最终结果
//        for (String name : list3) {
//            System.out.println(name);
//        }
    }
}

Stream 流的作用:结合了 Lambda 表达式,简化集合、数组的操作

Stream 流的使用步骤:

  1. 先得到一条 Stream 流(流水线),并把数据放上去

  2. 利用 Stream 流中的 API 进行各种操作

    • 中间方法(过滤、转换):方法调用完毕之后,还可以调用其它方法

    • 终结方法(统计、打印):最后一步,调用完毕之后,不能调用其它方法

  3. 使用中间方法对流水线上的数据进行操作

  4. 使用终结方法对流水线上的数据进行操作

获取方式 方法名 说明
单列集合 default Stream stream() Collection 中的默认方法
双列集合 无 无法直接使用 stream 流
数组 public static Stream stream(T[] array) Arrays 工具类中的静态方法
一堆零散数据 public static Stream of(T... values) Stream 接口中的静态方法

注:双列集合无法直接使用 stream 流,需要先用 keySet() 或 entrySet() 转成单列**集合

package com.faxont.stream;

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

public class StreamDemo2 {
    public static void main(String[] args) {
        /*
            单列集合            default Stream<E> stream()                         Collection 中的默认方法
            双列集合            无                                                  无法直接使用 stream 流
            数组              public static <T> Stream<T> stream(T[] array)    Arrays 工具类中的静态方法
            一堆零散数据      public static <T> Stream<T> of(T... values)         Stream 接口中的静态方法
         */

        // 1. 单列集合获取 Stream 流
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a", "b", "c", "d", "e");
//        // 获取一条流水线,并将集合中的元素放到流水线上
//        Stream<String> stream = list.stream();
//        // 使用终结方法 forEach 遍历打印流水线中的元素
//        stream.forEach(System.out::println);
        list.stream().forEach(System.out::println);
    }
}
package com.faxont.stream;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class StreamDemo3 {
    public static void main(String[] args) {
        /*
            双列集合        无       法直接使用 stream 流
         */

        // 1. 创建双列集合
        HashMap<String, Integer> hm = new HashMap<>();

        // 2. 添加数据
        hm.put("aaa", 111);
        hm.put("bbb", 222);
        hm.put("ccc", 333);
        hm.put("ddd", 444);

        // 3. 获取 Stream 流
        Set<Map.Entry<String, Integer>> entries = hm.entrySet();
        Set<String> keySet = hm.keySet();
        entries.stream().forEach(System.out::println);
        System.out.println("-----------------------");
        keySet.stream().forEach(System.out::println);
    }
}
package com.faxont.stream;

import java.util.Arrays;
import java.util.stream.Stream;

public class StreamDemo4 {
    public static void main(String[] args) {
        /*
            数组              public static <T> Stream<T> stream(T[] array)    Arrays 工具类中的静态方法
         */

        // 1. 创建数组
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

        String[] arr2 = {"a", "b", "c"};

        // 2. 获取 Stream 流
        Arrays.stream(arr).forEach(System.out::println);
        System.out.println("-----------------------");
        Arrays.stream(arr2).forEach(System.out::println);
        System.out.println("-----------------------");
        // 注意:
        // Stream 接口中静态方法 of 的细节
        // 方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组
        // 但是数组必须是引用数据类型的,如果传递基本数据类型,会把整个数组当作一个元素,放到 Stream 流当中
        Stream.of(arr).forEach(System.out::println);// [I@7cca494b
        System.out.println("-----------------------");
        Stream.of(arr2).forEach(System.out::println);
    }
}
package com.faxont.stream;

import java.util.stream.Stream;

public class StreamDemo5 {
    public static void main(String[] args) {
        /*
            一堆零散数据      public static <T> Stream<T> of(T... values)         Stream 接口中的静态方法
         */

        Stream.of(1, 2, 3, 4, 5).forEach(System.out::println);
        System.out.println("-----------------------");
        Stream.of("a", "b", "c", "d", "e").forEach(System.out::println);
    }
}

Stream 流的中间方法

名称 说明
Stream filter(Predicate<? super T> predicate) 过滤
Stream limit(long maxSize) 获取前几个元素
Stream skip(long n) 跳过前几个元素
Stream distinct() 元素去重,依赖(hashCode 和 equals 方法)
static Stream concat(Stream a, Stream b) 合并 a 和 b 两个流为一个流
Stream map(Function<T, R> mapper) 转换流中的数据类型

注意1:中间方法,返回新的 Stream 流,原来的 Stream 流只能使用一次,建议使用链式编程

注意2:修改 Stream 流中的数据,不会影响原来集合或者数组中的数据

package com.faxont.stream;

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

public class StreamDemo6 {
    public static void main(String[] args) {
        /*
            Stream<T> filter(Predicate<? super T> predicate)      过滤
            Stream<T> limit(long maxSize)                         获取前几个元素
            Stream<T> skip(long n)                                跳过前几个元素
         */

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

        // 1. 过滤        把张开头的留下,其余的过滤
        list.stream().filter(name -> name.startsWith("张")).forEach(System.out::println);
        System.out.println(list);// [张无忌, 周芷若, 赵敏, 张强, 张三丰, 张翠山, 张良, 王二麻子, 谢广坤]     集合本身没有改变
        System.out.println("-----------------------");

        // 2. 获取前几个元素
        list.stream().limit(3).forEach(System.out::println);
        System.out.println("-----------------------");

        // 3. 跳过前几个元素
        list.stream().skip(3).forEach(System.out::println);
        System.out.println("-----------------------");

        // 练习       张强, 张三丰, 张翠山
        list.stream().skip(3).limit(3).forEach(System.out::println);
        System.out.println("-----------------------");
        list.stream().limit(6).skip(3).forEach(System.out::println);
    }
}
package com.faxont.stream;

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

public class StreamDemo7 {
    public static void main(String[] args) {
        /*
            Stream<T> distinct()                                元素去重,依赖(hashCode 和 equals 方法)
            static <T> Stream<T> concat(Stream a, Stream b)     合并 a 和 b 两个流为一个流
         */

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

        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2, "周芷若", "赵敏");
        
        // 1. 元素去重,依赖(hashCode 和 equals 方法)
        list1.stream().distinct().forEach(System.out::println);
        System.out.println("-----------------------");

        // 2. 合并 a 和 b 两个流为一个流
        Stream.concat(list1.stream().distinct(), list2.stream()).forEach(System.out::println);
    }
}
package com.faxont.stream;

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

public class StreamDemo8 {
    public static void main(String[] args) {
        /*
            Stream<R> map(Function<T, R> mapper)    转换流中的数据类型
         */

        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌-15", "周芷若-14", "赵敏-13", "张强-20",
                "张三丰-100", "张翠山-40", "张良-35", "王二麻子-37", "谢广坤-41");

        // 只获取年龄并进行打印

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

        // apply 的形参 s:依次表示流里面的每一个数据
        // 返回值:转换之后的数据
        list.stream().map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                String[] split = s.split("-");
                int age = Integer.parseInt(split[1]);
                return age;
            }
        }).forEach(System.out::println);

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

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

Stream 流的终结方法

名称 说明
void forEach(Consumer action) 遍历
long count() 统计
toArray() 收集流中的数据,放到数组中
collect(Collector collector) 收集流中的数据,放到集合中
package com.faxont.stream;

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

public class StreamDemo9 {
    public static void main(String[] args) {
        /*
            void forEach(Consumer action)     遍历
            long count()                      统计
            toArray()                         收集流中的数据,放到数组中
         */

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

        // 1. 遍历
        // Consumer 的泛型:表示流中数据的类型
        // accept 方法的形参 s:依次表示流里面的每一个数据
        // 方法体:对每一个数据的处理操作(打印)
        list.stream().forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });
        System.out.println("-----------------------");
        list.stream().forEach(System.out::println);
        System.out.println("-----------------------");

        // 2. 统计
        long count = list.stream().count();
        System.out.println(count);
        System.out.println("-----------------------");

        // 3. 收集流中的数据,放到数组中
        // IntFunction<String[]> 泛型:表示数组的具体类型
        // apply 的形参:流中数据的个数,要跟数组的长度保持一致
        // apply 的返回值:具体类型的数组
        // 方法体:创建一个数组,并返回该数组

        // toArray 方法的参数的作用:负责创建一个指定类型的数组
        // toArray 方法的底层,会依次得到流里面的每一个数据,并把数据放到数组当中
        // toArray 方法的返回值,是一个装着流里面所有数据的数组
        String[] array = list.stream().toArray(new IntFunction<String[]>() {
            @Override
            public String[] apply(int value) {
                return new String[value];
            }
        });
        System.out.println(Arrays.toString(array));

        /**
         * 这属于 构造方法引用:
         * 语法:类名[]::new
         * 作用:生成一个 “能创建该类型数组” 的函数对象
         */
        String[] arr = list.stream().toArray(String[]::new);
        for (String s : arr) {
            System.out.println(s);
        }
    }
}
package com.faxont.stream;

import java.util.*;
import java.util.stream.Collectors;

public class StreamDemo10 {
    public static void main(String[] args) {
        /*
         collect(Collector collector)       收集流中的数据,放到集合中(List, Set, Map)

         注意:
            如果我们要把流的数据收集到 Map 集合中,键不能重复,否则会报错
         */

        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list, "张无忌-男-15", "张无忌-男-15", "周芷若-女-14", "赵敏-女-13", "张强-男-20",
                "张三丰-男-100", "张翠山-男-40", "张良-男-35", "王二麻子-男-37", "谢广坤-男-41");

        // 收集 List 集合当中
        // 需求
        // 把所有男性收集起来
        List<String> l = list.stream()
                .filter(s -> s.split("-")[1].equals("男"))
                .collect(Collectors.toList());
        System.out.println(l);

        // 收集 Set 集合当中
        // 需求
        // 把所有男性收集起来
        Set<String> set = list.stream()
                .filter(s -> s.split("-")[1].equals("男"))
                .collect(Collectors.toSet());
        System.out.println(set);

        // 收集 Map 集合当中
        // 需求
        // 把所有男性收集起来
        // key:姓名
        // value:年龄
        Map<String, Integer> map = list.stream()
                .filter(s -> s.split("-")[1].equals("男"))
                .distinct()
                .collect(Collectors.toMap(
                        s -> s.split("-")[0],
                        s -> Integer.parseInt(s.split("-")[2])));
        System.out.println(map);
    }
}

Stream 流练习

练习1:数据过滤

定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10

过滤奇数,只留下偶数。

并将结果保存起来

package com.faxont.practice;

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

public class Practice1 {
    public static void main(String[] args) {
        /*
            定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10
            过滤奇数,只留下偶数。
            并将结果保存起来
         */

        ArrayList<Integer> list = new ArrayList<>();
        Collections.addAll(list, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        list.stream()
                .filter(s -> s % 2 == 0)
                .forEach(System.out::println);
    }
}

练习2:数据操作

创建一个 ArrayList 集合,并添加以下字符串,字符串中前面是姓名,后面是年龄

"zhangsan, 23"

"lisi, 24"

"wangwu, 25"

保留年龄大于等于24岁的人,并将结果收集到 Map 集合中,姓名为键,年龄为值

package com.faxont.practice;

import java.util.ArrayList;
import java.util.Map;
import java.util.stream.Collectors;

public class Practice2 {
    public static void main(String[] args) {
        /*
            创建一个 ArrayList 集合,并添加以下字符串,字符串中前面是姓名,后面是年龄
            "zhangsan, 23"
            "lisi, 24"
            "wangwu, 25"
            保留年龄大于等于24岁的人,并将结果收集到 Map 集合中,姓名为键,年龄为值
         */

        ArrayList<String> list = new ArrayList<>();
        list.add("zhangsan, 23");
        list.add("lisi, 24");
        list.add("wangwu, 25");
        Map<String, Integer> map = list.stream()
                .filter(s -> Integer.parseInt(s.split(", ")[1]) >= 24)
                .collect(Collectors.toMap(
                        s -> s.split(", ")[0],
                        s -> Integer.parseInt(s.split(", ")[1])
                ));
        System.out.println(map);
    }
}

练习3:数据操作

现在有两个 ArrayList 集合,

第一个集合中:存储6名男演员的名字和年龄。第二个集合中:存储6名女演员的名字和年龄。

姓名和年龄中间用逗号隔开。比如:张三,23

要求完成如下操作:

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

备注:演员类 Actor,属性只要一个:name,age

package com.faxont.practice;

import java.util.ArrayList;
import java.util.Collections;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Practice3 {
    public static void main(String[] args) {
        /*
            现在有两个 ArrayList 集合,
            第一个集合中:存储6名男演员的名字和年龄。第二个集合中:存储6名女演员的名字和年龄。
            姓名和年龄中间用逗号隔开。比如:张三,23
            要求完成如下操作:
                1. 男演员只要名字为3个字的前两人
                2. 女演员只要姓杨的,并且不要第一个
                3. 把过滤后的男演员姓名和女演员姓名合并到一起
                4. 将上一步的演员信息封装成 Actor 对象
                5. 将所有的演员对象都保存到 List 集合中
            备注:演员类 Actor,属性只要一个:name,age

            男演员:"蔡坤坤,24","叶鞠咸,23","刘不甜,22","吴签,24","省嘉,30","肖滚滚,27"
            女演员:"赵小颖,35","杨颖,36","高元元,43","张天天,31","刘诗,35","杨小幂,33"
         */

        ArrayList<String> actorList = new ArrayList<>();
        Collections.addAll(actorList, "蔡坤坤,24", "叶鞠咸,23", "刘不甜,22", "吴签,24", "省嘉,30", "肖滚滚,27");
        ArrayList<String> actressList = new ArrayList<>();
        Collections.addAll(actressList, "赵小颖,35", "杨颖,36", "高元元,43", "张天天,31", "刘诗,35", "杨小幂,33");

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

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

        // 3. 把过滤后的男演员姓名和女演员姓名合并到一起
        Stream<String> stream3 = Stream.concat(stream1, stream2);

        // 4. 将上步的演员信息封装成 Actor 对象
        Stream<Actor> stream4 = stream3.map(s -> new Actor(s.split(",")[0], Integer.parseInt(s.split(",")[1])));

        // 5. 将所有的演员对象都保存到 List 集合中
        ArrayList<Actor> list = stream4.collect(Collectors.toCollection(ArrayList::new));
        System.out.println(list);
    }
}
package com.faxont.practice;

import java.util.Objects;

public class Actor {
    private String name;
    private int age;

    public Actor() {
    }

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

    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Actor actor = (Actor) o;
        return age == actor.age && Objects.equals(name, actor.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
posted @ 2026-04-20 21:48  弋湖  阅读(14)  评论(0)    收藏  举报