【Java学习】Stream流详解

news2024/9/22 5:36:07

 所属专栏:Java学习

在这里插入图片描述

Stream流是JDK 8引入的一个概念,它提供了一种高效且表达力强的方式来处理数据集合(如List、Set等)或数组。Stream API可以以声明性方式(指定做什么)来处理数据序列。流操作可以被分为两大类:中间操作(Intermediate Operations)和终端操作(Terminal Operations)。

🍁1. Stream流的适用对象

先得到一条Stream流,并把数据放上去,再进行中间操作和终端操作

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

 先来看单列集合的例子:

public class Demo1 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "a", "b", "c", "d", "e");
        // 获取Stream流,把集合中的数据放到流上
        Stream<String> stream1 = arrayList.stream();
        //内部类方式打印
        stream1.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.print(s);
            }
        });
        System.out.println();
        //获取流之后直接通过lambda表达式进行打印
        arrayList.stream().forEach(s -> System.out.print(s));
    }
}

对于双列集合,需要通过keySet() 或 entrySet() 转化为单列集合,再获取Stream 

public class Demo2 {
    public static void main(String[] args) {
        HashMap<String,Integer> hashMap = new HashMap<>();
        hashMap.put("aaa",1);
        hashMap.put("bbb",2);
        hashMap.put("ccc",3);
        hashMap.put("ddd",4);
        //双列集合第一种获取Stream流
        hashMap.keySet().stream().forEach(s -> System.out.print(s + " "));
        System.out.println();
        //双列集合第二种获取
        hashMap.entrySet().stream().forEach(s -> System.out.print(s + " "));
    }
}

 数组获取Stream流:

public class Demo3 {
    public static void main(String[] args) {
        int[] arr1 = {1, 2, 3, 4, 5};
        String[] arr2 = {"a", "b", "c", "d"};
        //获取Stream流
        Arrays.stream(arr1).forEach(s-> System.out.print(s + " "));
        System.out.println();
        //数组中是引用型数据类型也可以获取Stream流
        Arrays.stream(arr2).forEach(s -> System.out.print(s + " "));
    }
}

 对于不存储在数组或集合中的零散数据,可以直接通过Stream接口中的静态方法获取

public class Demo4 {
    public static void main(String[] args) {
        Stream.of(1,2,3,4,5).forEach(s-> System.out.print(s + " "));
        System.out.println();
        Stream.of("a","b","c").forEach(s-> System.out.print(s + " "));
    }
}

🍁2. 中间方法

中间操作:中间操作可以返回流本身,因此可以链式调用多个中间操作,中间操作可以是对流的过滤(如filter)、映射(如map)、排序(如sorted)等 

在上面的中间方法时,只会修改Stream流中的数据,不会影响原来集合或数组中的数据,并且原来的流只能使用一次

🍁2.1 filter()

filter 的参数 Predicate 是一个函数式接口 ,所以可以先使用匿名内部类的方式,再用 lambda 表达式

public class Demo5 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "aaa", "abc", "acb", "aa", "bb", "cc");
        //fitlter 过滤 把a开头的留下,其余数据不要
        arrayList.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                //返回值为true,当前数据留下,返回值为false,当前数据舍弃
                return s.startsWith("a");
            }
        }).forEach(s -> System.out.print(s + " "));
        System.out.println();
        // lambda表达式的形式
        arrayList.stream().filter(s -> s.startsWith("a")).forEach(s -> System.out.print(s + " "));
        System.out.println();
        //把stream流暂时接收的方式
        Stream<String> stream1 = arrayList.stream().filter(s -> s.startsWith("a"));
        stream1.forEach(s -> System.out.print(s + " "));
    }
}

由于Stream流只能用一次,如果之前的流已经被使用过,再次使用就会报错 

 所以说,由于只能使用一次,再用一个变量取接收也没有什么意义,直接使用链式编程就可以了

 并且,使用流之后,原来集合中的元素也不会改变

🍁2.2 limit() 和 skip()

/* limit() 获取前面几个元素
            skip() 跳过几个元素*/
        arrayList.stream().limit(3).forEach(s -> System.out.print(s + " "));
        System.out.println();
        arrayList.stream().skip(3).forEach(s -> System.out.print(s + " "));

🍁2.3 distinct()和concat()

distinct()去重是依赖hashCode()和equals()方法的,所以如果是自定义类型,要手动的重写这两个方法

public class Demo6 {
    public static void main(String[] args) {
        ArrayList<String> arrayList1 = new ArrayList<>();
        Collections.addAll(arrayList1, "aaa", "aaa", "acb", "aa", "bb", "cc");
        ArrayList<String> arrayList2 = new ArrayList<>();
        Collections.addAll(arrayList2,"dd","ee");
        //去重
        arrayList1.stream().distinct().forEach(s -> System.out.print(s + " "));
        System.out.println();
        //流的合并
        Stream.concat(arrayList1.stream(),arrayList2.stream()).forEach(s -> System.out.print(s + " "));
    }
}

🍁2.4 map()

需求:获取集合中的数字部分

首先调用split方法进行分割,得到数字部分之后再转换为整型

public class Demo7 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "aaa-11", "acb-22", "aa-33", "bb-44", "cc-55");
        // 获取集合中的数字部分
        arrayList.stream().map(new Function<String, Integer>() {
            @Override
            public Integer apply(String s) {
                //使用split进行分割
                String[] arr = s.split("-");
                //获取数字部分
                String num = arr[1];
                //转换为int类型
                int ans = Integer.parseInt(num);
                return ans;
            }
        }).forEach(s -> System.out.print(s + " "));
        System.out.println();
        //lambda表达式
        arrayList.stream()
                .map(s -> Integer.parseInt(s.split("-")[1]))
                .forEach(s -> System.out.print(s + " "));
    }
}

🍁3. 终结方法

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

🍁3.1 forEach()和count()

forEach方法在之前已经演示过了,就是进行遍历的

forEach中的参数Consumer也是一个函数式接口,也可以先使用匿名内部类的方式,再用 lambda 表达式

public class Demo8 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "aaa", "aaa", "acb", "aa", "bb", "cc");

        arrayList.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.print(s + " ");
            }
        });
        System.out.println();
        arrayList.forEach(s-> System.out.print(s + " "));
        System.out.println();

        //统计个数
        long l = arrayList.stream().count();
        System.out.println(l);
    }
}

count() 的返回值为long类型的,可以定义一个变量进行接收 

🍁3.2 toArray()

toArray()是收集流里面的数据放在数组中

toArray()方法有两种返回类型,一种是Object类型的,另一种是指定类型的,Object类型的比较简单,直接用Object类型的变量来接收就可以了

public class Demo9 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "aaa", "aaa", "acb", "aa", "bb", "cc");
        Object[] array1 = arrayList.stream().toArray();
        System.out.println(Arrays.toString(array1));
    }
}

接下来看指定类型

 toArray方法的参数也是一个函数式接口,还是使用匿名内部类和lambda表达式两种方式演示

public class Demo9 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "aaa", "aaa", "acb", "aa", "bb", "cc");
        
        //IntFunction的泛型:具体类型的数组
        //apply方法的形参:流中数据的个数,返回的数组的长度要一致
        //返回值就是具体类型的数组
        String[] array2 = arrayList.stream().toArray(new IntFunction<String[]>() {
            @Override
            public String[] apply(int value) {
                return new String[value];
            }
        });
        System.out.println(Arrays.toString(array2));
        //lambda表达式
        String[] array = arrayList.stream().toArray(value -> new String[value]);
        System.out.println(Arrays.toString(array));
    }
}

IntFunction的泛型是具体类型的数组
apply方法的形参表示流中数据的个数,返回的数组的长度要一致,最后的返回值就是具体类型的数组 

🍁3.3 collect() 

collect() 方法就是收集流里面的数据放到集合中,下面先来演示收集到List和Set集合中的例子

public class Demo10 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Collections.addAll(arrayList, "张三-男-23", "李四-男-21", "王五-女-22", "钱七-女-22");

        // 把所有男性收集起来
        //收集到List集合中
        List<String> list = arrayList.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toList());
        //收集到Set集合中
        Set<String> set = arrayList.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toSet());
    }
}

收集到List和Set集合中的数据的区别还是和List和Set集合的区别一样的,Set集合中不能有重复的元素,如果流中收集的数据存在重复的数据,在收集到Set集合之后就会进行去重

接下来看Map集合,由于Map集合是一个双列集合,所以需要指定键和值的生成规则

 这里的生成规则比较复杂

//收集到Map集合中
        /**
         * toMap : 参数一表示键的生成规则
         *         参数二表示值的生成规则
         * 参数一:
         * Function 泛型一:表示流中的数据类型
         *          泛型二:表示Map集合中键的类型
         * 方法 apply 形参:表示流中的每一个数据
         *           方法体:生成键的代码
         *           返回值:已经生成的键
         *
         */
        Map<String, Integer> map1 = arrayList.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .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);
//lambda表达式
        Map<String, Integer> map2 = arrayList.stream()
                .filter(s -> "男".equals(s.split("-")[1]))
                .collect(Collectors.toMap(s -> s.split("-")[0], s -> Integer.parseInt(s.split("-")[2])));
        System.out.println(map2);

 由于Map集合中是不能有重复的键的,所以如果Stream流获取的键中存在了重的元素,就会报错

🍁4. Stream流的作用和使用步骤总结

作用:Stream流就是结合了lambda表达式,简化集合和数组的操作

使用步骤:

1. 获取Stream流对象

2.使用中间方法处理数据

3.使用终结方法处理数据

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2047317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GD32 ADC配置跳坑

GD32 ADC配置跳坑 &#xff1a;时钟使能配置需在ADC前面 放在后面读取ADC值失败。 DMA配置放在ADC配置后面可以正常读取ADC的值 不同的模式选择可能会导致ADC存在读取失败的问题&#xff0c;红色部分是常用的模式&#xff0c;一般可以读取到相应的ADC的值 adc_software_trigge…

优雅谈大模型:Python编程篇

Python在机器学习领域的地位十分关键&#xff0c;虽然后面有Julia&#xff0c;Mojo等其他对手的挑战&#xff0c;然而Python拥有庞大的机器学习库和框架&#xff0c;尤其是生态系统比以往任何时候又强大了不少。从另外维度它和Java&#xff0c;Scala&#xff0c;Go&#xff0c;…

游戏安全入门-扫雷分析远程线程注入

前言 无论学习什么&#xff0c;首先&#xff0c;我们应该有个目标&#xff0c;那么入门windows游戏安全&#xff0c;脑海中浮现出来的一个游戏 – 扫雷&#xff0c;一款家喻户晓的游戏&#xff0c;虽然已经被大家分析的不能再透了&#xff0c;但是我觉得自己去分析一下还是极好…

适配器模式, 修饰器模式 与 代理模式

这三种模式, 感觉非常类似, 都是把核心类包一层, 在外部做一些额外的事情, 我还没发现他们之间具体的区别, 有想法的同学, 可以评论或者私聊我 适配器模式 简介: 就是在目标类外面包一层, 用以适配其他的模块,兼容整个程序框架 举个例子: 比如运动员, 中国运动员参加法国奥运…

市域社会治理平台规划建设方案

1. 建设背景与市域治理定义 市域社会治理作为国家治理体系的重要组成部分&#xff0c;具有承上启下的枢纽作用。2019年&#xff0c;全国市域社会治理现代化工作会议提出了推进市域社会治理现代化的总体思路&#xff0c;强调以城带乡、以点带面&#xff0c;明确了市域治理的方向…

[项目]文海泛舟测试报告

目录 一、项目背景 二、项目功能 三、功能测试 1. 测试用例&#xff1a; 2. 实际测试的部分&#xff08;含截图&#xff09; 1. 正常登录 2. 文章列表页显示/登录用户信息显示 3. 文章详情页内容显示/文章作者信息显示 4. 编辑功能 1. 点击“更新博客”按钮前 2. 点击…

前端开发攻略---Vue实现图像裁剪功能,支持用户通过图形界面进行裁剪区域的调整,最终生成裁剪后的图像。

目录 1、演示 2、实现原理 3、实现功能 4、代码 1、演示 2、实现原理 这里有详细介绍&#xff1a; 前端开发攻略---图片裁剪上传的原理-CSDN博客 3、实现功能 上传图像&#xff1a; 用户选择文件后&#xff0c;changeFile 方法读取文件内容并将其转换为 Data URL&#xff0c…

Amesim中动力电池建模方法与原则简介

引言 新能源动力电池一维仿真与三维仿真的主要区别在与&#xff0c;一维仿真中无法在仿真中精准的得到各个点的温度变化&#xff0c;其仅为质量块的平均温度。而在新能源动力电池一维仿真中&#xff0c;旨在对动力电池的策略、充放电时间等进行验证。而无论是策略还是充放电时…

jmreport测试数据库出现 权限不足,此功能需要分配角色 解决方法

目录 前言1. 问题所示2. 原理分析3. 解决方法前言 关于jmreport的补充可看官网:jmreport上线安全配置 1. 问题所示 jmreport测试数据库出现,出现如下所示的问题:权限不足,此功能需要分配角色! 截图如下所示: 2. 原理分析 对于原理分析的Bug,代表当前用户没有足够的…

HDFS的编程

一、HDFS原理 HDFS(Hadoop Distributed File System)是hadoop生态系统的一个重要组成部分,是hadoop中的的存储组件,在整个Hadoop中的地位非同一般,是最基础的一部分,因为它涉及到数据存储,MapReduce等计算模型都要依赖于存储在HDFS中的数据。HDFS是一个分布式文件系统,…

20款必试AI工具:轻松搞定设计到协作

随着人工智能技术的发展&#xff0c;各种AI工具如雨后春笋般涌现&#xff0c;给我们的工作和生活带来了极大便利。 在AI工具的海洋中&#xff0c;哪一款才是你的真命天子&#xff1f; 众所周知&#xff0c;AI工具如雨后春笋般涌现&#xff0c;让人目不暇接。面对琳琅满目的选…

Oracle 字符串转多行(REGEXP_SUBSTR)

方案一&#xff1a; SQL 1.一个数据表(TABLE1_ZK)中存在一个字段(STRS)&#xff08;存储格式是以【,】隔开的字符串&#xff09; 2.现需要将其查分为多行数据&#xff08;每行为其中一个字符串&#xff09; 3.sql SELECT t.id,REGEXP_SUBSTR(t.STRS, [^,], 1, LEVEL) AS ma…

招聘|头部云厂商招 PG 核心骨干 DBA【上海】

我们的招聘专区又回来了&#xff01;&#x1f3c3; Bytebase 作为先进的数据库 DevOps 团队协同工具 &#x1f527;&#xff0c;用户群里汇聚了 &#x1f497; 业界优秀的 DBA&#xff0c;SRE&#xff0c;运维的同学们 &#x1f31f;。 上周用户群里有小伙伴发招聘信息 &…

【观察者模式】设计模式系列: 实现与最佳实践案例分析

文章目录 观察者模式深入解析&#xff1a;在Java中的实现与应用1. 引言1.1 观察者模式简介1.2 模式的重要性及其在现实世界的应用示例1.3 本文的目标和读者定位 2. 观察者模式的基本概念2.1 定义与原理2.2 UML类图和时序图2.3 核心原则2.4 使用场景 3. 观察者模式与其他模式的关…

【数据结构】Java实现链表

目录 链表的概念 链表的实现 链表的功能 框架搭建 功能实现 打印链表 获取数据数量 查询数据 插入数据 头插法 尾插法 指定位置插入 删除数据 删除一个数据 删除多个相同数据 删除链表 完整代码 链表的概念 链表是一种物理存储结构上非连续存储结构&#xff0…

nosql----redis三主三从集群部署

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

【uniapp/uview1.x】解决在 u-popup 弹出层中使用 u-calendar 日历组件弹出方向出 bug 的问题

这个方法适用 uview 1.x 版本&#xff1b; 如果这个方法不适用可能是 uview 版本不一样&#xff0c;可以参考&#xff1a;https://github.com/dcloudio/uni-ui/issues/915 试试看 bug 的效果如图所示&#xff1a; 因为我为 popup 设置的方向为 top&#xff1a; <u-popup …

人工智能算法,图像识别技术;基于大语言模型的跨境商品识别与问答系统;图像识别

目录 一 .研究背景 二,大语言模型介绍 三,数据采集与预处理 商品识别算法 四. 跨境商品问答系统设计 五.需要源码联系 一 .研究背景 在当今全球化的背景下&#xff0c;跨境电商行业迅速发展&#xff0c;为消费者提供了更广泛的购物选择和更便利的购物方式。然而&#xf…

OLED屏幕制造工艺流程

OLED屏幕制造工艺流程是一个复杂且精细的过程&#xff0c;涉及多个关键步骤以确保最终的显示效果和性能。以下是OLED屏幕制造工艺流程的主要步骤&#xff1a; 1. 衬底制作与准备 材料选择&#xff1a;OLED器件需要一个透明的导电衬底&#xff0c;通常使用玻璃或塑料材料。 清…

集成RJ45网口网络变压器(网络隔离变压器)是如何影响网通设备的传输速率的。

华强盛电子导读RJ45连接器网口-199中间2643-0038 集成RJ45网口的网络变压器&#xff08;网络隔离变压器&#xff09;通常是指将网络变压器与RJ45连接器直接集成在一起的产品&#xff0c;这样的设计使得变压器可以直接安装在网络电缆的连接点上&#xff0c;而不需要额外的连接器…