使用Stream流写出优雅的高质量代码

news2024/9/25 3:28:26

前言

我们在开发中会大量的用到集合,少不了对集合进行一些操作,如何优雅的遍历集合,操作集合,不仅能体现出代码的质量,更能体现出程序员本身对自我的要求。
在这里插入图片描述

文章目录

  • 前言
  • 一、Stream初体验
  • 二、Stream流的使用
    • 2.1 获取流水线
    • 2.2 Stream流的中间方法
    • 2.3 Stream流的终结方法

一、Stream初体验

例如我们此时有这样的一个需求:把所有已“邓”字开头的元素,并且长度超过3的打印出来。

  • 常规方法实现
public class StreamDemo1 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"鹿晗","邓紫棋","吴青峰","邓超","许嵩");

        // 1.把所有以“邓”为开头的元素存储到新集合中
        List<String> list1 = new ArrayList<>();
        for (String name : list) {
             if (name.startsWith("邓")){
                 list1.add(name);
             }
        }

        // 2.把邓开头的,长度为3的元素再存储到新集合中
        List<String> list2 = new ArrayList<>();
        for (String name : list1) {
            if (name.length() == 3){
                list2.add(name);
            }
        }

        // 3.遍历打印最终结果
        for (String s : list2) {
            System.out.println(s);
        }
    }
}
  • 使用Stream流实现
public class StreamDemo1 {
    public static void main(String[] args) {

        List<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流的使用

  1. 先得到一条Stream流(流水线),并把数据放上去
  2. 使用中间方法对流水线上的数据进行操作
  3. 使用终结方法对流水线上的数据进行操作

2.1 获取流水线

数据类型方法说明
单列集合default Streamstream()Collection中的默认方法
双列集合无法直接使用Stream流
数组public staticStreamstream(T[]array)Arrays工具类中的静态方法
一堆零散数据public staticStreamof(T…values)Stream接口中的静态方法
// 1.单列集合获取Stream流
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"张三","李四","王五","张三丰");
        // 获取一条流水线,并把集合中的数据放到流水线上
        Stream<String> stream = list.stream();

// 2.双列集合获取Stream流
        Map<String,Integer> hm = new HashMap<>();
        // 2.1 添加数据
        hm.put("aaa",111);
        hm.put("bbb",222);
        hm.put("ccc",333);

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

        // 2.3 第二种获取stream流——键值对
        Stream<Map.Entry<String, Integer>> stream1 = hm.entrySet().stream();

// 3.数组获取Stream流
        int[] arr = {1,2,3,4,5,6};
        String[] arr2 = {"a","b","c"};
        
        // 3.1获取stream流
        IntStream stream = Arrays.stream(arr);
        Stream<String> stream1 = Arrays.stream(arr2);

// 4.一堆零散数据获取Stream流
        // 注意:方法的形参是一个可变参数,可以传递一堆零散的数据,也可以传递数组,但是数组必须是引用数据类型。如果传递基本数据类型,是会把整个数组当做一个元素,放到Stream中。
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);

2.2 Stream流的中间方法

  • filter:过滤
  • limit:获取前几个元素
  • skip:跳过前几个元素
  • distinct:元素重复,依赖(hashcode和equals方法)
  • concat:合并a和b两个流为一个流
  • map:转换流中的数据类型

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

public static void main(String[] args) {
        List<String> list1 = new ArrayList<>();
        Collections.addAll(list1,"张无忌","周芷若","赵敏","宋青书","张三丰","独孤求败","张无忌","张无忌");
        List<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"张无忌","周芷若","赵敏");

        // 过滤
        list1.stream().filter(s -> s.startsWith("张")).forEach(s-> System.out.println(s));
        // 获取前几个
        list1.stream().limit(3).forEach(s-> System.out.println(s));
        // 跳过
        list1.stream().skip(4).forEach(s-> System.out.println(s));
		// 去重
		list1.stream().distinct().forEach(s -> System.out.println(s));
		// 合并
		Stream.concat(list1.stream(),list2.stream()).forEach(s -> System.out.println(s));

    }
}

map:转换流中的数据类型

List<String> list = new ArrayList<>();
Collections.addAll(list,"张无忌-15","周芷若-20","赵敏-14","宋青书-19","张三丰-90","独孤求败-101");
        /**
         * map 转换流中的数据类型
         * String->int
         * 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(s-> System.out.println(s));

// lambda表达式书写
list.stream().map(s ->
            Integer.parseInt(s.split("-")[1])).forEach(s-> System.out.println(s));

2.3 Stream流的终结方法

  • forEach:遍历
  • count:统计
  • toArray:收集流中的数据,放到数组中
  • collect:收集流中的数据,放到集合中(List、Set、Map)

我们先创建一个User类,方便我们后续的操作

public class User implements Serializable {
    private String name;
    private Integer age;
    private String sex;

    public User() {
    }

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

    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;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}
List<User> userList = new ArrayList<>();
Collections.addAll(userList,new User("张无忌",15,"男"),
        new User("张无忌",15,"男"),
        new User("张三丰",90,"男"),
        new User("赵敏",16,"女"),
        new User("周芷若",20,"女"));

// forEach:遍历
userList.stream().forEach(new Consumer<User>() {
    @Override
    public void accept(User user) {
       System.out.println(user.toString());
    }
});
userList.stream().forEach(user -> System.out.println(user.toString()));
// count:统计
long count = userList.stream().count();

收集流中的数据,放到数组中

/**
 * IntFunction的泛型:具体类型的数组
 * apply的形参:流中数据的个数,要跟数组的长度保持一致
 * apply的返回值:具体类型的数组
 * 方法体:就是创建数组
 */
 User[] userArray = userList.stream().toArray(new IntFunction<User[]>() {
      @Override
      public User[] apply(int value) {
          return new User[value];
      }
 });
 // lambda表达式简化上述代码
 User[] userArray = userList.stream().toArray(value -> new User[value]);
 System.out.println(Arrays.toString(userArray));

toArray方法的参数作用:负责创建一个指定类型的数组。底层:会依次得到流里面的每一个数据,并把数据放到数当中。返回值:是一个装着流里面所有数据的数组

收集流中的数据,放到List集合中

// 获取姓张的用户
List<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌","周芷若","赵敏","宋青书","张三丰","独孤求败","张无忌","张无忌");
List<String> stringList = list1.stream().filter(s -> s.startsWith("张")).collect(Collectors.toList());
System.out.println(stringList);

收集流中的数据,放到Set集合中

List<String> list1 = new ArrayList<>();
Collections.addAll(list1,"张无忌","周芷若","赵敏","宋青书","张三丰","独孤求败","张无忌","张无忌");
Set<String> stringSet = list1.stream().filter(s -> s.startsWith("张")).collect(Collectors.toSet());

因为Set是不可重复的,所以会自动去重

收集流中的数据,放到Map集合中

List<User> userList = new ArrayList<>();
Collections.addAll(userList,new User("张无忌",15,"男"),
        new User("张三丰",90,"男"),
        new User("赵敏",16,"女"),
        new User("周芷若",20,"女"));
/**
 * toMap:
 * 参数一表示键的生成规则
 * 参数二表示值得生成规则
 *
 * 参数一:Function泛型一:表示流中每一个数据的类型
 *                泛型二:表示Map集合中键的数据类型
 *       方法apply形参:依次表示流中的每一个数据
 *               方法体:生成键的代码
 *               返回值:已经生成的键
 * 参数二:Function泛型一:表示流中每一个数据的类型
 *                泛型二:表示Map集合中值的数据类型
 *       方法apply形参:依次表示流中的每一个数据
 *               方法体:生成值的代码
 *               返回值:已经生成的值
 */
Map<String, Integer> map = userList.stream().filter(user -> "男".equals(user.getSex())).collect(Collectors.toMap(new Function<User, String>() {
    @Override
    public String apply(User user) {
        return user.getName();
    }
}, new Function<User, Integer>() {
    @Override
    public Integer apply(User user) {
        return user.getAge();
    }
 }));
// lambda表达式简化上述代码
Map<String, Integer> map = userList.stream().filter(user -> "男".equals(user.getSex()))
                .collect(Collectors.toMap(user -> user.getName(), user -> user.getAge()));
System.out.println(map);

OK,以上内容就是Stream流的一些主要使用方法,当然还有很多实用的方法,例如Order By排序,Group By分组等。
小伙伴们自行去研究学习一下吧~

原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下

👍 点赞,你的认可是我创作的动力! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!

⭐️ 收藏,你的青睐是我努力的方向! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!

✏️ 评论,你的意见是我进步的财富! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!

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

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

相关文章

python实现人脸识别(face_recognition)

一、定义 1、介绍 本项目是世界上最强大、简洁的人脸识别库&#xff0c;你可以使用Python和命令行工具提取、识别、操作人脸。 本项目的人脸识别是基于业内领先的C开源库dlib中的深度学习模型&#xff0c;用Labeled Faces in the Wild人脸数据集进行测试&#xff0c;有高达99…

ESP32(一):Win10配置 IDF+VSCode

一、安装包下载&#xff1a; Git&#xff1a;Git for WindowsPython&#xff1a;Download Python | Python.org以Windows x86-64开头的是 64 位的 Python 安装程序&#xff1b;以Windows x86开头的是 32 位的 Python 安装程序。ESP-IDF&#xff08;选择Offline版本&#xff09…

Kettle安装与使用

一、Kettle简介 Kettle最早是一个开源的ETL&#xff08;Extract-Transform-Load的缩写&#xff09;工具&#xff0c;全称为KDE Extraction, Transportation, Transformation and Loading Environment。后来Kettle重命名为Pentaho Data Integration 。它由Java开发&#xff0c;…

数据结构学习记录——堆的删除(思路图解、代码实现、逐段解析)

目录 堆的删除&#xff08;最大堆&#xff09; 思路 代码 解析 堆的删除&#xff08;最大堆&#xff09; 思路 代码 ElementType DeleteMax( MaxHeap H ) { /* 从最大堆H中取出键值为最大的元素&#xff0c;并删除一个结点 */int Parent, Child;ElementType MaxItem, X…

戴尔Alienware m18r1原厂win11中文系统 带F12 Support Assist OS Recovery恢复功能

戴尔Alienware m18r1原厂win11中文系统 带F12 Support Assist OS Recovery一键恢复功能 恢复各机型预装系统&#xff0c;带所有dell主题壁纸、dell软件驱动、带戴尔SupportAssist OS Recovery恢复功能&#xff0c;一次性恢复成新机状态&#xff0c;并且以后不用重装系统&#…

手把手教你学习IEC104协议和编程实现 十三-写定值

直接进入主题,要想写入定值,首先要确定写入的是那个定值区,毕竟按照iec104的规定,定值区有8个为0~7,那么就首先涉及到了,切换定值区的过程,执行过程如下: 切换定值区 我们看到,TI=200=0xC8h 我们先设计一个按钮,用于切换定值区。如下图: 在这个按钮的相应的消息上…

【Docker_image_source】docker设置国内镜像源

关于Docker镜像源的设置 国内加速地址 1.Docker中国区官方镜像 https://registry.docker-cn.com 2.网易 http://hub-mirror.c.163.com 3.ustc https://docker.mirrors.ustc.edu.cn 4.中国科技大学 https://docker.mirrors.ustc.edu.cn 5.阿里云容器 生成自己的加速地址 登录&am…

升级企业数智化底座 用友iuap拉满长期主义

本文转自 深度 我们普遍认为&#xff0c;人类社会经历了工业革命、电气革命&#xff0c;现在正奔赴从信息革命到智能革命的道路上&#xff0c;这一过程迫切且不可逆。 因此&#xff0c;《“十四五”数字经济发展规划》指出&#xff0c;以数字技术与实体经济深度融合为主线&a…

JavaScript:数组---双指针法

文章目录 双指针法27.移除元素为什么返回值是整数&#xff0c;但输出的答案是数组&#xff1f;双指针法 977.有序数组的平方暴力法&#xff1a;先平方再排序双指针法 总结双指针 双指针法 27.移除元素 为什么返回值是整数&#xff0c;但输出的答案是数组&#xff1f; 双指针法…

阿里工作7年,肝到P8就剩这份学习笔记了,已助朋友拿到20个Offer

在阿里工作了7年&#xff0c;工作压力大&#xff0c;节奏快&#xff0c;但是从技术上确实得到了成长&#xff0c;尤其是当你维护与大促相关的系统的时候&#xff0c;熬到P7也费了不少心思&#xff0c;小编也是个爱学习的人&#xff0c;把这几年的工作经验整理成了一份完整的笔记…

3.13 结构体嵌套、大小及位域

目录 结构体嵌套结构体 结构体的大小 位域 结构体嵌套结构体 含义 结构体中的成员可以是另一个结构体 语法 struct 结构体名 { struct 结构体名 成员名&#xff1b; }; 结构体中共同的变量可以单独放出来&#xff0c;单独封装一个结构体 结构体的大小 字节对齐 含义 …

微服务篇:开始从头到尾搭建第一个微服务(小白)

微服务篇 我的一个微服务 手把手写微服务项目&#xff0c;从现在开始 文章目录 微服务篇环境搭建开发工具开发环境 一、创建项目&#xff1a;创建gitee链接1、登录 gitee 创建仓库2、 给项目起一个名字&#xff08;本地名字要跟远端一致哦&#xff09; panda3、打开IDEA创建项…

19. Unity - 2D游戏开发小记02 --- 伪透视图、2D物体碰撞、瓦片地图碰撞、素材缩放平铺

1. 伪视图 在2D游戏开发当中,当角色移动时,会发生物体与物体之间的前后遮挡。2D视图中的前后关系是由 Y 轴决定,y 值越小物体越靠前。unity的渲染应开启根据 y 值的大小进行渲染才能保证正确的遮挡效果,在菜单栏Editor–>project setting --> Graphic中按照下图方式…

MySQL之Doublewrite Buffer详解

前言 本文已收录在MySQL性能优化原理实战专栏&#xff0c;点击此处浏览更多优质内容。 上一篇文章MySQL之Adaptive Hash Index详解我们学习了InnoDB Adaptive Hash Index自适应哈希索引的工作原理。其本质是将频繁访问数据页的索引键值以“Key”放在缓存中&#xff0c;“Value”…

【微机原理】汇编指令之传送指令

目录 一、传送类指令 1.MOV 传送指令 2.XCHG 传送指令 二、LEA 有效地址传送指令 三.堆栈操作指令 &#xff08;1&#xff09;入栈指令&#xff1a;PUSH &#xff08;2&#xff09;出栈指令&#xff1a;POP 四、输入输出指令 &#xff08;1&#xff09;IN 输入指令 &#xff08…

nginx部署本地启动vue项目

需求&#xff1a;就是想在本地不运行vue项目&#xff0c;可以直接访问到打包后的vue项目 1.安装nginx nginx: download&#xff0c;这里我安装的1.12.2稳定版本 2.下载完直接得到一个压缩包&#xff0c;直接把它解压到一个目录 &#xff01;&#xff01;&#xff01;&#x…

CSI指纹预处理(中值、均值、Hampel、维纳滤波、状态统计滤波器)

目录 前言 1、箱线法 2、中值滤波器 3、均值滤波器 4、Hampel滤波器 5、维纳滤波 6、状态统计滤波器 前言 因为设备、温度和实验室物品摆设等因素的影响&#xff0c;未经处理的CSI数据不能直接使用&#xff0c;需要对数据进行异常值处理以保证数据的稳定性&#xff0c;…

力扣刷题2023-05-04-1——题目:2614. 对角线上的质数

题目&#xff1a; 给你一个下标从 0 开始的二维整数数组 nums 。 返回位于 nums 至少一条 对角线 上的最大 质数 。如果任一对角线上均不存在质数&#xff0c;返回 0 。 注意&#xff1a; 如果某个整数大于 1 &#xff0c;且不存在除 1 和自身之外的正整数因子&#xff0c;…

【前端】1、flex 布局

flex 布局目录 一、flex container 和 flex items二、用在 flex container 上的 CSS 属性(1) flex-direction(2) justify-content(3) align-items 三、用在 flex items 上的 CSS 属性 一、flex container 和 flex items &#x1f384; 1、开启了 Flex 布局的元素叫 flex cont…

系统分析师---系统规划高频错题

系统规划---成本效益分析 评价信息系统经济效益常用的方法主要有成本效益分析法&#xff0c;投入产出分析法和价值工程方法。盈亏平衡法常用于销售定价&#xff1b; 可行性分析 系统规划是信息系统生命周期的第一个阶段&#xff0c;其任务是对企业的环境、目标以及现有系统的…