Java 8 Stream API的使用

news2024/11/16 5:35:01

一、什么是Stream?

Stream(流)是一个来自数据源的元素队列,它可以支持聚合操作。

  • 数据源:流的数据来源,构造Stream对象的数据源,比如通过一个List来构造Stream对象,这个List就是数据源;
  • 聚合操作:对Stream对象进行处理后使得Stream对象返回指定规则数据的操作称之为聚合操作,比如filter、map、limit、sorted等都是聚合操作。

二、Stream 聚合操作

UmsMenu是一个菜单对象,具有树形结构,对象定义如下。

public class UmsMenu implements Serializable {
    private Long id;

    @ApiModelProperty(value = "父级ID")
    private Long parentId;

    @ApiModelProperty(value = "创建时间")
    private Date createTime;

    @ApiModelProperty(value = "菜单名称")
    private String title;

    @ApiModelProperty(value = "菜单级数")
    private Integer level;

    @ApiModelProperty(value = "菜单排序")
    private Integer sort;

    @ApiModelProperty(value = "前端名称")
    private String name;

    @ApiModelProperty(value = "前端图标")
    private String icon;

    @ApiModelProperty(value = "前端隐藏")
    private Integer hidden;

    //省略所有getter及setter方法
}

三、Stream对象的创建

Stream对象分为两种,一种串行的流对象,一种并行的流对象。

// menuList指所有菜单列表
// 为集合创建串行流对象
Stream<UmsMenu> stream = menuList.stream();
// 为集合创建并行流对象
Stream<UmsMenu> parallelStream = menuList.parallelStream();

四、filter

对Stream中的元素进行过滤操作,当设置条件返回true时返回相应元素。

@Test
public void filterTest(){
    //filter操作:获取所有一级菜单
    List<UmsMenu> oneLevelList = menuList.stream()
    .filter(menu -> menu.getParentId() == 0L)
    .collect(Collectors.toList());
    LOGGER.info("filter操作:{}",oneLevelList);
}

五、map

        对Stream中的元素进行转换处理后获取,比如可以将UmsMenu对象转换成Long对象。我们经常会有这样的需求:需要把某些对象的id提取出来,然后根据这些id去查询其他对象,这时可以使用此方法。

@Test
public void mapTest(){
    //map操作:获取所有菜单的id
    List<Long> idList = menuList.stream()
    .map(menu -> menu.getId())
    .collect(Collectors.toList());
    LOGGER.info("map操作:{}",idList);
}

六、limit

从Stream中获取指定数量的元素。

@Test
public void limitTest(){
    //limit操作:获取前5个菜单
    List<UmsMenu> firstFiveList = menuList.stream()
            .limit(5)
            .collect(Collectors.toList());
    LOGGER.info("limit操作:{}",firstFiveList);
}

七、count

仅获取Stream中元素的个数。

@Test
public void countTest(){
    //count操作:获取所有一级菜单的个数
    long count = menuList.stream()
    .filter(menu -> menu.getParentId() == 0L)
    .count();
    LOGGER.info("count操作:{}",count);
}

八、sorted

对Stream中元素按指定规则进行排序。

@Test
public void sortedTest(){
    //sorted操作:将所有菜单按照sort字段进行排序
    List<UmsMenu> sortedList = menuList.stream()
            .sorted((menu1,menu2)->{return menu2.getSort().compareTo(menu1.getSort());})
            .collect(Collectors.toList());
    LOGGER.info("sorted操作:{}",sortedList);
}

九、skip

跳过指定个数的Stream中元素,获取后面的元素。

@Test
public void skipTest(){
    //skip操作:跳过前5个元素,返回后面的
    List<UmsMenu> skipList = menuList.stream()
            .skip(5)
            .collect(Collectors.toList());
    LOGGER.info("skip操作:{}",skipList);
}

十、应用

        我们经常会有返回树形结构数据的需求。比如这里的菜单,具有一级菜单、二级菜单、三级菜单这样的结构。如果我们要返回一个集合,包含菜单以及菜单下面嵌套的子菜单,使用Stream API可以很方便的解决这个问题。

        注意:这里我们的菜单上下级之间以parentId来关联,parentId是指上一级菜单的id,顶级菜单的parentId为0。

定义包含下级菜单的对象

继承自UmsMenu对象,只增加了一个children属性,用于存储下级菜单。

/**
 * @description 后台菜单节点封装
 */
@Getter
@Setter
public class UmsMenuNode extends UmsMenu {
    @ApiModelProperty(value = "子级菜单")
    private List<UmsMenuNode> children;
}

定义获取树形结构的方法

        我们先过滤出parentId为0的顶级菜单,然后给每个顶级菜单设置其子级菜单,covertMenuNode方法的主要用途就是从所有菜单中找出相应子级菜单。

@Override
public List<UmsMenuNode> treeList() {
    List<UmsMenu> menuList = menuMapper.selectByExample(new UmsMenuExample());
    List<UmsMenuNode> result = menuList.stream()
    .filter(menu -> menu.getParentId().equals(0L))
    .map(menu -> covertMenuNode(menu, menuList)).collect(Collectors.toList());
    return result;
}

为每个菜单设置子级菜单

        这里我们使用filter操作来过滤出每个菜单的子级菜单,由于子级菜单下面可能还会有子级菜单,这里我们使用递归来解决。但是递归操作什么时候停止,这里把递归调用方法放到了map操作中去,当没有子级菜单时filter下的map操作便不会再执行,从而停止递归。

/**
 * 将UmsMenu转化为UmsMenuNode并设置children属性
 */
private UmsMenuNode covertMenuNode(UmsMenu menu, List<UmsMenu> menuList) {
    UmsMenuNode node = new UmsMenuNode();
    BeanUtils.copyProperties(menu, node);
    List<UmsMenuNode> children = menuList.stream()
            .filter(subMenu -> subMenu.getParentId().equals(menu.getId()))
            .map(subMenu -> covertMenuNode(subMenu, menuList)).collect(Collectors.toList());
    node.setChildren(children);
    return node;
}

 用collect方法将List转成map

有时候我们需要反复对List中的对象根据id进行查询,我们可以先把该List转换为以id为key的map结构,然后再通过map.get(id)来获取对象,这样比较方便。

@Test
public void collect2mapTest(){
    //collect转map操作:将菜单列表以id为key,以菜单对象为值转换成map
    Map<Long, UmsMenu> menuMap = menuList.stream()
            .collect(Collectors.toMap(menu -> menu.getId(), menu -> menu));
    LOGGER.info("collect转map操作:{}",menuMap);
}

 数学运算

    public void testNumberCalculate() {
        List<Integer> ids = Arrays.asList(10, 20, 30, 40, 50);
        // 计算平均值
        Double average = ids.stream().collect(Collectors.averagingInt(value -> value));
        System.out.println("平均值:" + average);
        // 数据统计信息
        IntSummaryStatistics summary = ids.stream().collect(Collectors.summarizingInt(value -> value));
        System.out.println("数据统计信息: " + summary);
}

生成拼接字符串

    public void testCollectJoinStrings() {
        List<String> ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193");
        String joinResult = ids.stream().collect(Collectors.joining(","));
        System.out.println("拼接后:" + joinResult);
}

生成集合

    public void testCollectStopOptions() {
        List<User> ids = Arrays.asList(new User(17), new User(22), new User(23));
        // collect成list
        List<User> collectList = ids.stream().filter(dept -> dept.getId() > 20)
                .collect(Collectors.toList());
        System.out.println("collectList:" + collectList);
        // collect成Set
        Set<User> collectSet = ids.stream().filter(dept -> dept.getId() > 20)
                .collect(Collectors.toSet());
        System.out.println("collectSet:" + collectSet);
        // collect成HashMap,key为id,value为Dept对象
        Map<Integer, User> collectMap = ids.stream().filter(dept -> dept.getId() > 20)
                .collect(Collectors.toMap(User::getId, dept -> dept));
        System.out.println("collectMap:" + collectMap);
    }

一旦一个Stream被执行了终止操作之后,后续便不可以再读这个流执行其他的操作了,否则会报错

    public void testHandleStreamAfterClosed() {
        List<String> ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193");
        Stream<String> stream = ids.stream().filter(s -> s.length() > 2);
        // 统计stream操作后剩余的元素个数
        System.out.println(stream.count());
        System.out.println("-----下面会报错-----");
        // 判断是否有元素值等于205
        try {
            System.out.println(stream.anyMatch("205"::equals));
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("-----上面会报错-----");
    }

 简单结果终止方法

    public void testSimpleStopOptions() {
        List<String> ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193");
        // 统计stream操作后剩余的元素个数
        System.out.println(ids.stream().filter(s -> s.length() > 2).count());
        // 判断是否有元素值等于205
        System.out.println(ids.stream().filter(s -> s.length() > 2).anyMatch("205"::equals));
        // findFirst操作
        ids.stream().filter(s -> s.length() > 2)
                .findFirst()
                .ifPresent(s -> System.out.println("findFirst:" + s));
    }

filter、sorted、distinct、limit

    public void testGetTargetUsers() {
        List<String> ids = Arrays.asList("205", "10", "308", "49", "627", "193", "111", "193");
        // 使用流操作
        List<User> results = ids.stream()
                .filter(s -> s.length() > 2)
                .distinct()
                .map(Integer::valueOf)
                .sorted(Comparator.comparingInt(o -> o))
                .limit(3)
                .map(id -> new User(id))
                .collect(Collectors.toList());
        System.out.println(results);
    }

演示map的用途:一对多转换

    public void stringToIntFlatmap() {
        List<String> sentences = Arrays.asList("hello world", "Jia Gou Wu Dao");
        // 使用流操作
        List<String> results = sentences.stream()
                .flatMap(sentence -> Arrays.stream(sentence.split(" ")))
                .collect(Collectors.toList());
        System.out.println(results);
    }

 

演示map的用途:一对一转换

    public void stringToIntMap() {
        List<String> ids = Arrays.asList("205", "105", "308", "469", "627", "193", "111");
        // 使用流操作
        List<User> results = ids.stream()
                .map(id -> {
                    User user = new User(Integer.valueOf(id));
                    return user;
                })
                .collect(Collectors.toList());
        System.out.println(results);
    }

补充:Java 8 新特性

JDK的前世今生:细数 Java5 - 15 的那些经典特性

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

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

相关文章

ardupilot开发 --- RealSense-D400 篇

目录 0. 一些概念1. 用windows检查设备是否正常1. 使用 Intel RealSense SDK 2.0 查看相机图像数据 0. 一些概念 官网&#xff1a;添加链接描述选型&#xff1a;D455 1. 用windows检查设备是否正常 用USB连接D455与PC 下载 Intel.RealSense.Viewer.exe 并打开&#xff0c;设…

ACE框架学习3

ACE Acceptor-Connector框架 该框架实现 Acceptor-Connector 模式&#xff0c;该模式解除了“网络化应用中的协作对端服务的连接和初始化”与“连接和初始化之后它们所执行的处理”的耦合。Acceptor-Connector 框架允许成用独立于它们所提供的服务来配置其连接布局的关键属性。…

正版软件 | Reg Organizer - 适用于 Windows 的注册表清理工具软件 教程分享

什么是 Reg Organizer &#xff1f; Reg Organizer 是一套用于维护和优化 Windows 操作系统的工具。 通过使用 Reg Organizer&#xff0c;您可以清理系统中无用的文件&#xff0c;优化启动应用程序&#xff0c;编辑 Windows 注册表&#xff0c;搜索和替换注册表项和值&#…

Xtuner微调笔记

Xtuner学习视频 两种微调范式 在指令微调的过程中&#xff0c;需要高质量的对话数据。 而构建高质量的对话&#xff08;指令&#xff09;数据&#xff0c;则涉及到以下流程 先通过system/user/assistant的json格式来构造对话模板&#xff0c;把问题和期望模型做出的回答通过…

Q1笔记本电脑线上市场发展现状:大盘下滑,深耕细分市场是机会

今年&#xff0c;宏观经济环境的恶化和笔记本电脑需求的持续放缓&#xff0c;导致全球笔记本电脑出货量&#xff0c;尤其是线上市场的整体状态不容乐观。 根据鲸参谋数据显示&#xff0c;今年Q1笔记本在线上市场&#xff08;京东天猫淘宝&#xff09;综合销量约250万件&#x…

如何禁用WordPress的自动更新(包括主题、插件和核心文件)

这几天发现我的一个网站突然打不开了&#xff0c;提示“此站点遇到了致命错误”,如图&#xff1a; 这个网站一直都是正常运行的&#xff0c;最近也没有过什么更新&#xff0c;按理说不应该会出现问题&#xff0c;我担心可能是主机方面做了什么调整导致&#xff0c;所以联系了Ho…

ShaderLab的混合命令

文章目录 示例原理混合因子混合操作参考 示例 Pass {Tags{"LightMode" "ForwardBase"}// 关闭深度写入ZWrite Off// 设置Pass的混合模式&#xff0c;SrcAlpha: 片元着色器产生的颜色的混合因子// OneMinusSrcAlpha 已经存在于颜色缓冲中的颜色的混合因子…

idea 的使用和安装 以及简介

Java开发工具 大家刚才写代码的时候都是用记事本写的&#xff0c;但是有没有觉得记事本写代码不太方便啊&#xff01;记事本写代码单词写错了没有提示&#xff0c;格式也不好调整&#xff0c;写代码之后还需要我们到命令行使用javac命令手动编译&#xff0c;然后运行。 有没有一…

[NISACTF 2022]bilala的二维码

​​​​​​​NSSCTF{M0RS34ND282X231} 还有一个是像素我找不到

Docker 简单使用及安装常用软件

一、Docker 安装、配置与卸载 1.1、Docker 安装 # 1.安装gcc环境 yum -y install gcc gcc-c && \# 2. 卸载docker旧版本&#xff08;可能之前有安装&#xff09; yum -y remove docker docker-common docker-selinux docker-engine && \# 3. 安装依赖的软件包…

易错知识点(学习过程中不断记录)

快捷键专区&#xff1a; 注释&#xff1a;ctrl/ ctrlshift/ 保存&#xff1a;ctrls 调试&#xff1a; 知识点专区&#xff1a; 1基本数据类型 基本数据类型有四类&#xff1a;整型、浮点型、字符型、布尔型&#xff08;Boolean&#xff09;&#xff0c; 分为八种&#xff…

房产中介小程序高效开发攻略:从模板到上线一站式服务

对于房产中介而言&#xff0c;拥有一个高效且用户友好的小程序是提升业务、增强客户黏性的关键。而采用直接复制模板的开发方式&#xff0c;无疑是实现这一目标的最佳途径&#xff0c;不仅简单快捷&#xff0c;而且性价比极高。 在众多小程序模板开发平台中&#xff0c;乔拓云网…

国外企业使用生成式人工智能实例100

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

电脑使用笔记

1.电脑亮度调节 亮度&#xff1a;50 对比度&#xff1a;45 暗部平衡&#xff1a;40

Unity inputSystem 读取输入值的方法

1&#xff1a;通过关在 PlayerInput 获取 设置后之后在同意物体上挂载C# 脚本 通过事件获得 2&#xff1a; 生成 C#脚本 通过C# 脚本获得 3&#xff1a;通过回调函数

计算机网络——应用层协议(1)

在这篇文章初识网络中&#xff0c;我介绍了关于计算机网络的相关知识&#xff0c;以及在这两篇文章中Socket编程和Socket编程——tcp&#xff0c;介绍了使用套接字在两种协议下的网络间通信方式。本篇文章中我将会进一步介绍网络中网络协议的部分&#xff0c;而这将会从应用层开…

如何修改php版本

我使用的Hostease的Windows虚拟主机产品,由于网站程序需要支持高版本的PHP,程序已经上传到主机&#xff0c;但是没有找到切换PHP以及查看PHP有哪些版本的位置&#xff0c;因此咨询了Hostease的技术支持&#xff0c;寻求帮助了解到可以实现在Plesk面板上找到此切换PHP版本的按钮…

学习100个Unity Shader (14) ---透明效果

文章目录 渲染队列透明度测试&#xff08;Alpha Test&#xff09;效果Shader 透明度混合&#xff08;Alpha Blending&#xff09;效果Shader 参考 渲染队列 由”Queue“ 标签决定&#xff0c;索引号越小越早被渲染&#xff1a; 名称队列索引号Background1000Geometry2000Alph…

Java后端如何生成二维码

为节约服务器资源&#xff0c;一般情况下&#xff0c;不要直接生成海量二维码。 可以考虑&#xff0c;前缀字符&#xff0c;自定义规则生成二维码。 支持自定义二维码大小、二维码logo、颜色等等 前端生成二维码 详见前端开发手册 附件&#xff1a;代码文件下载 ​​http…

03-JAVA设计模式-模板方法模式

模板方法模式 什么是模板方法 模板方法模式&#xff08;Template Method Pattern&#xff09;在Java中是一种行为型设计模式&#xff0c;它定义了一个操作中的算法骨架&#xff0c;而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某…