Java中Stream流的使用示例详解

 更新时间:2025年08月19日 09:56:46   作者:Ting-yu  
Stream流提供了一种高效且易于使用的方式来对数据进行过滤、映射、排序、聚合等操作,使代码更加简洁和可读,接下来通过本文给大家介绍Java中Stream流的使用,感兴趣的朋友跟随小编一起看看吧

在 Java 中,Stream 流是 Java 8 引入的一个强大特性,它允许你以声明式的方式处理集合数据。Stream 流提供了一种高效且易于使用的方式来对数据进行过滤、映射、排序、聚合等操作,使代码更加简洁和可读。

1. 获取Stream流

要使用Stream流首先要获取到Stream流

public static void main(String[] args) {
        //创建Stream流
        //1. 单列集合创建
        List<String> list = new ArrayList<>();
        Stream<?> stream1 = list.stream();
        Set<String> set = new HashSet<>();
        Stream<?> stream2 = set.stream();
        Stack<String> stack = new Stack<>();
        Stream<?> stream3 = stack.stream();
        Queue<String> queue = new LinkedList<>();
        Stream<?> stream4 = stack.stream();
        //2. 双列集合创建
        Map<String, String> map = new HashMap<>();
        Stream<?> stream5 = map.entrySet().stream();
        //3. 数组创建
        int[] arr = {1, 2 ,3};
        IntStream stream6 = Arrays.stream(arr);
        //4. 零散数据创建
        Stream<?> stream7 = Stream.of(1, 2, 3, 4);
    }

 注意 Stream.of(T... values) values为变长参数可以接收一个数组,但是这里只能接收引用类型的数组,如果是基础类型的数据由于不会自动装包会把整个数组视为一个数据

2. 中间方法

当我们获取到Stream流后就可以调用其中的一些方法来对其中的数据进行一些操作,其中的方法分为两大类,其一就是中间方法,中间方法的特点是会返回一个新的 Stream 流,允许你链式调用多个操作 :

  • Stream<T> filter(Predicate<T>):过滤满足条件的元素。
  • Stream<T> limit(long):限制元素数量。
  • Stream<T> skip(long):跳过前 n 个元素。
  • Stream<T> distinct():去重。
  • static<T> Stream<T> concat(Stream,Stream ):合并a和两个流作为一个流
  • Stream<T> sorted():排序。
  • Stream<T> map(Function<T, R>):将元素转换为另一种类型。

 注意:

  • 每个Stream流只能使用一次,中间方法返回的是一个新的Stream流
  • 修改Stream流中的数据不会影响原来集合或数组中的数据

 2.1 filter使用示例

 filter方法接收一个Predicate类型的参数,我们转到其定义:

可以看到这是一个函数式接口, 同时test方法的描述也说明了,如果参数匹配则返回true否则返回false,这里的含义即为,如果该数据(t)是符合要求的则通过,否则不通过:

    public static void filterTest() {
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "张明", "张三丰", "张良", "张明朱诺", "杨过", "小龙女");
        //这里筛选以张开头且长度为3的字符串
        list.stream()
                .filter(s -> s.startsWith("张"))
                .filter(s -> s.length() == 3)
                .forEach(x-> System.out.print(x + " "));
    }

这里我们使用lambad表达式重写test方法,先赛选了以张开头的数据,再赛选了长度为3的数据最后使用forEach输出

2.2 limit 和skip使用

limit接收一个long类型的参数表示只保留前n个元素,skip同样接收一个long类型的参数表示要跳过前n个元素:

    public static void limitAndSkipTest() {
        List<String> list = new ArrayList<>();
        Collections.addAll(list, "张明", "张三丰", "张良", "张明朱诺", "杨过", "小龙女");
        System.out.println("limit:");
        list.stream()
                .limit(4)
                .forEach(x-> System.out.print(x + " "));
        System.out.println("\nskip:");
        list.stream()
                .skip(3)
                .forEach(x-> System.out.print(x + " "));
        System.out.println("\nlimit-skip:");
        list.stream()
                .limit(4)
                .skip(3)
                .forEach(x-> System.out.print(x + " "));
        System.out.println("\nskip-limit:");
        list.stream()
                .skip(3)
                .limit(4)
                .forEach(x-> System.out.print(x + " "));
    }

运行结果:

2.3 distinct 和concat

    public static void distinctAndConcatTest() {
        List<String> list1 = new ArrayList<>();
        Collections.addAll(list1, "张三丰", "张三丰", "杨过", "张明朱诺", "杨过", "小龙女");
        List<String> list2 = new ArrayList<>();
        Collections.addAll(list2, "张明", "张三丰", "迪迦");
        System.out.println("\ndistinct:");
        list1.stream()
                .distinct()
                .forEach(x-> System.out.print(x + " "));
        System.out.println("\nconcat:");
        Stream.concat(list1.stream(), list2.stream())
                .forEach(x-> System.out.print(x + " "));
    }

运行结果:

 2.4 stored使用

    public static void sortedTest() {
        List<String> list1 = new ArrayList<>();
        Collections.addAll(list1, "张明", "张三丰", "迪迦");
        List<Integer> list2 = new ArrayList<>();
        Collections.addAll(list2, 1, 2, 3);
        System.out.println("\nsortedList1:");
        list1.stream()
                .sorted()
                .forEach(x-> System.out.print(x + " "));
        System.out.println("\nsortedList2:");
        list2.stream()
                .sorted()
                .forEach(x-> System.out.print(x + " "));
        System.out.println("\nsortedList2desc:");
        list2.stream()
                .sorted(((o1, o2) -> o2 - o1))
                .forEach(x-> System.out.print(x + " "));
    }

sorted不传参数时默认是排降序,可以传入比较器自定义排序规则

2.5 map使用

    public static void MapTest() {
        List<String> list1 = new ArrayList<>();
        Collections.addAll(list1, "张明-16", "张三丰-23", "迪迦-3000");
        //获取每个人的年龄
        /**
         * 第一个参数对应原本的数据类型,第二个参数代表要转成的数据类型
         */
        list1.stream().map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                return Integer.parseInt(s.split("-")[1]);
            }
        }).forEach(x-> System.out.print(x + " "));
        System.out.println();
        //使用lambada表达式
        list1.stream()
                .map(s -> Integer.parseInt(s.split("-")[1]))
                .forEach(x-> System.out.print(x + " "));
    }

运行结果:

3. 终结方法

可以理解为结束方法,不会再返回Stream流

常用的终结方法有:

  • forEach(Consumer<T>):遍历每个元素。
  • count():计算元素数量。
  • toArray():将元素转换为数组。
  • collect(Collector<T, A, R>):将元素收集到集合中。

 3.1 forEach/count/toArray()使用

    public static void CountAndToArrayTest() {
        List<String> list1 = new ArrayList<>();
        Collections.addAll(list1, "张三丰", "张三丰", "杨过", "张明朱诺", "杨过", "小龙女");
        List<Integer> list2 = new ArrayList<>();
        Collections.addAll(list2, 1, 2, 3);
        System.out.println(list1.stream().count());
        System.out.println(list2.stream().count());
        //<>为需要创建的数组的类型
        String[] str = list1.stream().toArray(new IntFunction<String[]>() {
            @Override
            public String[] apply(int value) {
                //value代表数据的数量,我们返回一个长度大于等于value的数据即可
                return new String[value];
            }
        });
        System.out.println(Arrays.toString(str));
        //使用lambada表达式
        Integer[] arr = list2.stream().toArray(value -> new Integer[value]);
        System.out.println(Arrays.toString(arr));
    }

3.2 collect 使用

将流中的元素收集到集合中

    public static void CollectTest() {
        List<String> list1 = new ArrayList<>();
        Collections.addAll(list1, "张三丰-男-23", "杨过-男-32", "张三丰-男-23", "张明朱诺-女-19", "小龙女-女-18");
        //收集所有男性
        //List
        List<String> list = list1.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toList());
        System.out.println(list);
        //Set
        Set<String> set = list1.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toSet());
        System.out.println(set);
        //Map
        //收集男性,名字作为键,年龄作为值
        Map<String, Integer> map1 = list1.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .distinct()//map中key不能重复,所以先去重
                .collect(Collectors.toMap(
                        new Function<String, String>() {
                            @Override
                            public String apply(String s) {
                                return s.split("-")[0];
                            }
                        },
                        new Function<String, Integer>() {
                            @Override
                            public Integer apply(String s) {
                                return Integer.parseInt(s.split("-")[2]);
                            }
                        }
                ));
        System.out.println(map1);
        //使用lambada表达式
        Map<String, Integer> map2 = list1.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .distinct()//map中key不能重复,所以先去重
                .collect(Collectors.toMap(
                        s -> s.split("-")[0],
                        s -> Integer.parseInt(s.split("-")[2])
                ));
        System.out.println(map2);
    }

这里特别说明toMap()方法,

可以看到toMap接收两个Function做为参数,这里通过参数名我们不难猜出,一个作为键,一个作为值,于是我们只需实现Function接口重写其中方法使其返回预期的键/值即可。

到此这篇关于Java中Stream流的使用的文章就介绍到这了,更多相关java stream流使用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java Socket无法完全接收返回内容的解决方案

    java Socket无法完全接收返回内容的解决方案

    这篇文章主要介绍了java Socket无法完全接收返回内容的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • 一文详解SpringBoot如何使用pageHelper做分页处理

    一文详解SpringBoot如何使用pageHelper做分页处理

    分页是常见大型项目都需要的一个功能,PageHelper是一个非常流行的MyBatis分页插件,下面就跟随小编一起来了解下SpringBoot是如何使用pageHelper做分页处理的吧
    2025-03-03
  • SpringBoot接口数据加解密实战记录

    SpringBoot接口数据加解密实战记录

    现今对于大多数公司来说,信息安全工作尤为重要,下面这篇文章主要给大家介绍了关于SpringBoot接口数据加解密的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • idea乱码修改bin目录下的idea.exe.vmoptions无效问题

    idea乱码修改bin目录下的idea.exe.vmoptions无效问题

    这篇文章主要介绍了idea乱码修改bin目录下的idea.exe.vmoptions无效问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • SpringBoot实现整合微信支付方法详解

    SpringBoot实现整合微信支付方法详解

    这篇文章主要介绍了SpringBoot实现整合微信支付的过程详解,文中的示例代码对我们的工作或学习有一定的帮助,感兴趣的小伙伴可以跟随小编学习一下
    2021-12-12
  • SpringBoot整合Redis实现热点数据缓存的示例代码

    SpringBoot整合Redis实现热点数据缓存的示例代码

    这篇文章主要介绍了SpringBoot中整合Redis实现热点数据缓存,本文以IDEA + SpringBoot作为 Java中整合Redis的使用 的测试环境,结合实例代码给大家详细讲解,需要的朋友可以参考下
    2023-03-03
  • Java线程中断的本质深入理解

    Java线程中断的本质深入理解

    Java的中断是一种协作机制。也就是说调用线程对象的interrupt方法并不一定就中断了正在运行的线程,它只是要求线程自己在合适的时机中断自己,本文将详细介绍,需要了解的朋友可以参考下
    2012-12-12
  • Maven项目中读取src/main/resources目录下的配置文件的方法

    Maven项目中读取src/main/resources目录下的配置文件的方法

    本篇文章主要介绍了Maven项目中读取src/main/resources目录下的配置文件的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • 详解MyBatis的SqlSession获取流程

    详解MyBatis的SqlSession获取流程

    SqlSession的获取是通过SqlSessionFactory的openSession() 方法,那么具体的获取流程是什么,所以本文就给大家详细讲解一下MyBatis的SqlSession获取流程,需要的朋友可以参考下
    2023-07-07
  • Java 处理高并发负载类优化方法案例详解

    Java 处理高并发负载类优化方法案例详解

    这篇文章主要介绍了Java 处理高并发负载类优化方法案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08

最新评论