Java 集合数据处理技巧:使用 Stream API 实现多种操作

news2025/3/24 12:44:28

20250217135513828919.png

在 Java 开发中,对集合数据进行处理是非常常见的需求,例如去重、排序、分组、求和等。Java 8 引入的 Stream API 为我们提供了一种简洁、高效的方式来处理集合数据。本文将详细介绍如何使用 Stream API 实现多种集合数据处理操作,并给出相应的代码示例。

1. List 根据某个属性去重

在处理 List​ 数据时,有时需要根据对象的某个属性进行去重。可以使用 TreeSet​ 和 Stream​ 来实现这一功能。以下是示例代码:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
import java.util.stream.Collectors;

// 定义 SKU 类
class SKU {
    private String gid;

    public SKU(String gid) {
        this.gid = gid;
    }

    public String getGid() {
        return gid;
    }
}

public class ListDistinctByProperty {
    public static void main(String[] args) {
        List<SKU> skuList = new ArrayList<>();
        skuList.add(new SKU("1"));
        skuList.add(new SKU("2"));
        skuList.add(new SKU("1"));

        ArrayList<SKU> skus = skuList.stream().collect(
                Collectors.collectingAndThen(
                        Collectors.toCollection(
                                () -> new TreeSet<>(Comparator.comparing(SKU::getGid))
                        ), ArrayList::new
                )
        );

        skus.forEach(sku -> System.out.println(sku.getGid()));
    }
}

在上述代码中,首先创建了一个 SKU​ 类,包含 gid​ 属性。然后使用 Stream​ 对 skuList​ 进行处理,通过 Collectors.toCollection​ 将其转换为 TreeSet​,利用 TreeSet​ 的特性根据 gid​ 去重,最后再将 TreeSet​ 转换为 ArrayList​。

2. 指定字段排序

2.1 升序排序

可以使用 Stream​ 的 sorted​ 方法和 Comparator.comparing​ 来实现指定字段的升序排序。以下是示例代码:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

// 定义 Order 类
class Order {
    private long createTime;

    public Order(long createTime) {
        this.createTime = createTime;
    }

    public long getCreateTime() {
        return createTime;
    }
}

public class ListSortAsc {
    public static void main(String[] args) {
        List<Order> orderList = new ArrayList<>();
        orderList.add(new Order(3));
        orderList.add(new Order(1));
        orderList.add(new Order(2));

        List<Order> sortedList = orderList.stream()
               .sorted(Comparator.comparing(Order::getCreateTime))
               .collect(Collectors.toList());

        sortedList.forEach(order -> System.out.println(order.getCreateTime()));
    }
}

2.2 降序排序

如果需要降序排序,只需在 Comparator.comparing​ 后调用 reversed​ 方法。以下是示例代码:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

// 定义 Order 类
class Order {
    private long createTime;

    public Order(long createTime) {
        this.createTime = createTime;
    }

    public long getCreateTime() {
        return createTime;
    }
}

public class ListSortDesc {
    public static void main(String[] args) {
        List<Order> orderList = new ArrayList<>();
        orderList.add(new Order(3));
        orderList.add(new Order(1));
        orderList.add(new Order(2));

        List<Order> sortedList = orderList.stream()
               .sorted(Comparator.comparing(Order::getCreateTime).reversed())
               .collect(Collectors.toList());

        sortedList.forEach(order -> System.out.println(order.getCreateTime()));
    }
}

2.3 null 排前面

如果需要将 null​ 值排在前面,可以使用 Comparator.nullsFirst​ 方法。以下是示例代码:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

// 定义 LuckyBoysVo 类
class LuckyBoysVo {
    private Date usageTime;

    public LuckyBoysVo(Date usageTime) {
        this.usageTime = usageTime;
    }

    public Date getUsageTime() {
        return usageTime;
    }
}

public class ListSortNullFirst {
    public static void main(String[] args) {
        List<LuckyBoysVo> luckyBoysList = new ArrayList<>();
        luckyBoysList.add(new LuckyBoysVo(new Date(2000)));
        luckyBoysList.add(new LuckyBoysVo(null));
        luckyBoysList.add(new LuckyBoysVo(new Date(1000)));

        List<LuckyBoysVo> luckyBoysVoList = luckyBoysList.stream()
               .sorted(Comparator.comparing(LuckyBoysVo::getUsageTime, Comparator.nullsFirst(Date::compareTo)))
               .collect(Collectors.toList());

        luckyBoysVoList.forEach(vo -> System.out.println(vo.getUsageTime()));
    }
}

3. 指定字段相同,指定值计算和

可以使用 Collectors.groupingBy​ 方法对数据进行分组,然后使用 reduce​ 方法计算相同字段对应的值的和。以下是示例代码:

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

// 定义 ExportAgentVo 类
class ExportAgentVo {
    private String dealCode;
    private String agentId;
    private String goodsId;
    private String goodName;
    private int count;
    private String name;
    private String address;

    public ExportAgentVo(String dealCode, String agentId, String goodsId, String goodName, int count, String name, String address) {
        this.dealCode = dealCode;
        this.agentId = agentId;
        this.goodsId = goodsId;
        this.goodName = goodName;
        this.count = count;
        this.name = name;
        this.address = address;
    }

    public String getDealCode() {
        return dealCode;
    }

    public String getAgentId() {
        return agentId;
    }

    public String getGoodsId() {
        return goodsId;
    }

    public String getGoodName() {
        return goodName;
    }

    public int getCount() {
        return count;
    }

    public String getName() {
        return name;
    }

    public String getAddress() {
        return address;
    }
}

public class ListSumByField {
    public static void main(String[] args) {
        List<ExportAgentVo> exportAgentVoList = new ArrayList<>();
        exportAgentVoList.add(new ExportAgentVo("1", "A", "G1", "Good1", 10, "Name1", "Addr1"));
        exportAgentVoList.add(new ExportAgentVo("2", "A", "G1", "Good1", 20, "Name1", "Addr1"));
        List<ExportAgentVo> exportAgentVoListResult = new ArrayList<>();

        exportAgentVoList.stream()
               .collect(Collectors.groupingBy(o -> (o.getGoodsId() + o.getAgentId()), Collectors.toList()))
               .forEach((id, transfer) -> {
                    transfer.stream()
                           .reduce((a, b) ->
                                    new ExportAgentVo(a.getDealCode(),
                                            a.getAgentId(),
                                            a.getGoodsId(),
                                            a.getGoodName(),
                                            a.getCount() + b.getCount(), a.getName(), a.getAddress())
                            )
                           .ifPresent(exportAgentVoListResult::add);
                });

        exportAgentVoListResult.forEach(vo -> System.out.println(vo.getCount()));
    }
}

4. 指定字段相同,计算相同个数

可以使用 Collectors.groupingBy​ 和 Collectors.counting​ 方法来计算指定字段相同的个数。以下是示例代码:

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

// 定义 TkDetailMaskLayerMapping 类
class TkDetailMaskLayerMapping {
    private String maskId;

    public TkDetailMaskLayerMapping(String maskId) {
        this.maskId = maskId;
    }

    public String getMaskId() {
        return maskId;
    }
}

public class ListCountByField {
    public static void main(String[] args) {
        List<TkDetailMaskLayerMapping> list = new ArrayList<>();
        list.add(new TkDetailMaskLayerMapping("M1"));
        list.add(new TkDetailMaskLayerMapping("M1"));
        list.add(new TkDetailMaskLayerMapping("M2"));

        Map<String, Long> map = list.stream()
               .collect(Collectors.groupingBy(TkDetailMaskLayerMapping::getMaskId, Collectors.counting()));

        map.forEach((key, value) -> System.out.println(key + ": " + value));
    }
}

5. 指定字段分组

可以使用 Collectors.groupingBy​ 方法对 List​ 进行指定字段分组。以下是示例代码:

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

// 定义 ExportAgentVo 类
class ExportAgentVo {
    private String agentId;

    public ExportAgentVo(String agentId) {
        this.agentId = agentId;
    }

    public String getAgentId() {
        return agentId;
    }
}

public class ListGroupByField {
    public static void main(String[] args) {
        List<ExportAgentVo> exportAgentVoListResult = new ArrayList<>();
        exportAgentVoListResult.add(new ExportAgentVo("A1"));
        exportAgentVoListResult.add(new ExportAgentVo("A2"));
        exportAgentVoListResult.add(new ExportAgentVo("A1"));

        Map<String, List<ExportAgentVo>> exportAgentVoMap = exportAgentVoListResult.stream()
               .collect(Collectors.groupingBy(ExportAgentVo::getAgentId));

        exportAgentVoMap.forEach((key, value) -> System.out.println(key + ": " + value.size()));
    }
}

6. 分组并求和

可以使用 Collectors.groupingBy​ 和 Collectors.summingInt​ 方法对数据进行分组并求和。以下是示例代码:

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

// 定义 ExportGoodsProcurementDetailVo 类
class ExportGoodsProcurementDetailVo {
    private String supplierName;
    private String agentId;
    private String goodsId;
    private int count;

    public ExportGoodsProcurementDetailVo(String supplierName, String agentId, String goodsId, int count) {
        this.supplierName = supplierName;
        this.agentId = agentId;
        this.goodsId = goodsId;
        this.count = count;
    }

    public String getSupplierName() {
        return supplierName;
    }

    public String getAgentId() {
        return agentId;
    }

    public String getGoodsId() {
        return goodsId;
    }

    public int getCount() {
        return count;
    }
}

public class ListGroupAndSum {
    public static void main(String[] args) {
        List<ExportGoodsProcurementDetailVo> goodsProcurementDetailVos = new ArrayList<>();
        goodsProcurementDetailVos.add(new ExportGoodsProcurementDetailVo("S1", "A1", "G1", 10));
        goodsProcurementDetailVos.add(new ExportGoodsProcurementDetailVo("S1", "A1", "G1", 20));
        ExportGoodsProcurementDetailVo exportGoodsProcurementDetailVo = new ExportGoodsProcurementDetailVo("S1", "A1", "", 0);
        ExportGoodsProcurementDetailVo exportGoBeerVo = new ExportGoodsProcurementDetailVo("", "A1", "", 0);

        Map<String, Integer> goodCountMap = goodsProcurementDetailVos.stream()
               .filter(a -> a.getSupplierName().equals(exportGoodsProcurementDetailVo.getSupplierName())
                        && a.getAgentId().equals(exportGoBeerVo.getAgentId()))
               .collect(Collectors.groupingBy(ExportGoodsProcurementDetailVo::getGoodsId,
                        Collectors.summingInt(ExportGoodsProcurementDetailVo::getCount)));

        goodCountMap.forEach((key, value) -> System.out.println(key + ": " + value));
    }
}

7. List 转 Map

可以使用 Collectors.toMap​ 方法将 List​ 转换为 Map​。需要注意的是,如果集合对象有重复的 key​,会报错 Duplicate key​,可以使用 (k1, k2) -> k1​ 来处理重复 key​ 的情况。以下是示例代码:

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

// 定义 CustomerDetailResp 类
class CustomerDetailResp {
    private String dept;
    private String members;

    public CustomerDetailResp(String dept, String members) {
        this.dept = dept;
        this.members = members;
    }

    public String getDept() {
        return dept;
    }

    public String getMembers() {
        return members;
    }
}

// 定义 Apple 类
class Apple {
    private int id;

    public Apple(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }
}

public class ListToMap {
    public static void main(String[] args) {
        List<CustomerDetailResp> result = new ArrayList<>();
        result.add(new CustomerDetailResp("D1", "M1"));
        result.add(new CustomerDetailResp("D2", "M2"));

        Map<String, String> map1 = result.stream().collect(Collectors.toMap(CustomerDetailResp::getDept, CustomerDetailResp::getMembers));
        Map<String, CustomerDetailResp> map2 = result.stream().collect(Collectors.toMap(CustomerDetailResp::getDept, CustomerDetailResp -> CustomerDetailResp));

        List<Apple> appleList = new ArrayList<>();
        appleList.add(new Apple(1));
        appleList.add(new Apple(1));
        Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a, (k1, k2) -> k1));
    }
}

8. List 转 String

可以使用 Google Guava 库的 Joiner​ 类将 List​ 转换为 String​。以下是示例代码:

import com.google.common.base.Joiner;
import java.util.ArrayList;
import java.util.List;

public class ListToString {
    public static void main(String[] args) {
        List<String> itemNoList = new ArrayList<>();
        itemNoList.add("1");
        itemNoList.add("2");
        itemNoList.add("3");

        String join = Joiner.on(',').join(itemNoList);
        System.out.println(join);
    }
}

9. String 转 List

可以使用 Arrays.stream​ 和 Collectors.toList​ 方法将 String​ 转换为 List​。以下是示例代码:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StringToList {
    public static void main(String[] args) {
        String sales = "1,2,3,2";
        List<String> saleList = Arrays.stream(sales.split(",")).distinct().collect(Collectors.toList());
        saleList.forEach(System.out::println);
    }
}

通过以上示例,我们可以看到 Java 8 的 Stream API 为集合数据处理提供了非常强大和便捷的功能。合理使用这些功能可以大大提高代码的可读性和开发效率。本文示例已涵盖日常开发中90%的集合处理场景,建议根据具体业务需求灵活组合使用。对于更复杂的操作,可结合Collectors.joining、mapping等收集器实现。

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

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

相关文章

OSI 参考模型和 TCP/IP 参考模型

数据通信是很复杂的&#xff0c;很难在一个协议中完成所有功能。因此在制定协议时经常采用的思路是将复杂的数据通信功能由若干协议分别完成&#xff0c;然后将这些协议按照一定的方式组织起来。最典型的是采用分层的方式来组织协议&#xff0c;每一层都有一套清晰明确的功能和…

SD NAND 的 SDIO在STM32上的应用详解(上篇)

目录 上篇&#xff1a; 一.SDIO简介 二.SD卡简介/内部结构 1.SD卡/SD NAND引脚 2.SD卡寄存器 3.FLASH存储器 三.SDIO总线拓扑 中篇&#xff1a; 四.SDIO功能框图(重点) 1.SDIO适配器 2.控制单元 3.命令通道(重点) 4.数…

基于图像处理的裂缝检测与特征提取

一、引言 裂缝检测是基础设施监测中至关重要的一项任务,尤其是在土木工程和建筑工程领域。随着自动化技术的发展,传统的人工巡检方法逐渐被基于图像分析的自动化检测系统所取代。通过计算机视觉和图像处理技术,能够高效、精确地提取裂缝的几何特征,如长度、宽度、方向、面…

执行pnpm run dev报错:node:events:491 throw er; // Unhandled ‘error‘ event的解决方案

vite搭建的vue项目&#xff0c;使用pnpm包管理工具&#xff0c;执行pnpm run dev&#xff0c;报如下错误&#xff1a; 报错原因&#xff1a; pnpm依赖安装不完整&#xff0c;缺少esbuild.exe文件&#xff0c;导致无法执行启动命令。 解决方案&#xff1a; 根据错误提示中提到…

「软件设计模式」建造者模式(Builder)

深入解析建造者模式&#xff1a;用C打造灵活对象构建流水线 引言&#xff1a;当对象构建遇上排列组合 在开发复杂业务系统时&#xff0c;你是否经常面对这样的类&#xff1a;它有20个成员变量&#xff0c;其中5个是必填项&#xff0c;15个是可选项。当用户需要创建豪华套餐A&…

uniapp 安卓10+ 选择并上传文件

plus.io.chooseFile({title: 选择文件,filetypes: [mp3], // 允许的文件类型multiple: false, // 是否允许多选}, (res) > {console.log(虚拟路径666&#xff1a;, res);var arr[{name: files,uri: res.files[0],}]let obj {"tableName": "mingmen_daily_mi…

【第1章:深度学习概览——1.6 深度学习框架简介与选择建议】

嘿,各位老铁们,今天咱们来一场深度学习框架的深度探索之旅。在这个充满无限可能的深度学习时代,深度学习框架就像是连接理论与实践的桥梁,帮助我们从算法设计走向实际应用。随着技术的飞速发展,深度学习框架的选择变得越来越多样化,每一种框架都有其独特的优势和适用场景…

网页制作02-html,css,javascript初认识のhtml的文字与段落标记

用一首李白的将进酒,对文字与段落标记进行一个简单的介绍演示&#xff1a; 目录 一、标题字 1、标题字标记h 2、标题字对其属性align 二、文本基本标记 1、字体属性face 2、字号属性size 3、颜色属性 Color 三、文本格式化标记 1、粗体标记 b &#xff0c;strong 2、…

一.数据治理理论架构

1、数据治理核心思想&#xff1a; 数据治理理论架构图描绘了一个由顶层设计、管控机制、核心领域和管理系统四个主要部分组成的数据治理框架。它旨在通过系统化的方法&#xff0c;解决数据治理机制缺失引发的业务和技术问题&#xff0c;并最终提升企业的数据管理水平。 数据治…

PHP基础部分

但凡是和输入、写入相关的一定要预防别人植入恶意代码! HTML部分 语句格式 <br> <hr> 分割符 <p>插入一行 按住shift 输入! 然后按回车可快速输入html代码(VsCode需要先安装live server插件) html:<h1>标题 数字越大越往后</h1> <p…

人工智能 - 主动视觉可能就是你所需要的:在双臂机器人操作中探索主动视觉

AV-ALOHA 系统使用用于 AV 的 VR 耳机实现直观的数据收集&#xff0c;并且 用于作的 VR 控制器或引线臂。这有助于捕捉全身和头部 远程作我们的真实和模拟系统的运动&#xff0c;记录来自 6 个的视频 不同的摄像头&#xff0c;并为我们的 AV 仿制学习策略提供训练数据。 加州大…

DeepSeek 助力 Vue 开发:打造丝滑的日期选择器(Date Picker),未使用第三方插件

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

Kafka偏移量管理全攻略:从基础概念到高级操作实战

#作者&#xff1a;猎人 文章目录 前言&#xff1a;概念剖析kafka的两种位移消费位移消息的位移位移的提交自动提交手动提交 1、使用--to-earliest重置消费组消费指定topic进度2、使用--to-offset重置消费offset3、使用--to-datetime策略指定时间重置offset4、使用--to-current…

一周学会Flask3 Python Web开发-Debug模式开启

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 默认情况&#xff0c;项目开发是普通模式&#xff0c;也就是你修改了代码&#xff0c;必须重启项目&#xff0c;新代码才生效&…

java练习(28)

ps&#xff1a;练习来自力扣 给定一个二叉树&#xff0c;判断它是否是平衡二叉树 // 定义二叉树节点类 class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val val; }TreeNode(int val, TreeNode left, TreeNode right) {this.va…

Web安全|渗透测试|网络安全

基础入门(P1-P5) p1概念名词 1.1域名 什么是域名&#xff1f; 域名&#xff1a;是由一串用点分隔的名字组成的Internet上某一台计算机或计算机组的名称&#xff0c;用于在数据传输时对计算机的定位标识&#xff08;有时也指地理位置&#xff09;。 什么是二级域名多级域名&am…

OpenHarmony 系统性能优化——默认关闭全局动画

笔者最近发现&#xff0c;关闭OpenHarmony全局动画&#xff0c;系统UI的响应速度会极大的提升 1.全局动画的开关由系统属性persist.sys.arkui.animationscale来控制&#xff0c;默认为1。也就是 动画缩放 1x 2.如果让persist.sys.arkui.animationscale默认为0,也就是关闭的状态…

C 程序多线程拆分文件

C 程序多线程拆分文件 在C语言中&#xff0c;实现多线程来拆分文件通常需要借助多线程库&#xff0c;比如 POSIX 线程库&#xff08;pthread&#xff09;或者 Windows 的线程库&#xff08;CreateThread 或类似的函数&#xff09;。下面我将分别展示在 Linux 和 Windows 环境下…

【Linux】Ubuntu Linux 系统——Python集成开发环境

ℹ️大家好&#xff0c;我是练小杰&#xff0c;今天周四了&#xff0c;明天就周五了&#xff0c;再坚持坚持又能休息了&#xff01;&#xff01;&#x1f606; 本文是有关Linux 操作系统中Python集成开发环境基础知识&#xff0c;后续将添加更多相关知识噢&#xff0c;谢谢各位…

数据库加密全解析:从传输到存储的安全实践

title: 数据库加密全解析:从传输到存储的安全实践 date: 2025/2/17 updated: 2025/2/17 author: cmdragon excerpt: 数据加密是数据库安全的最后一道物理防线。传输层SSL/TLS配置、存储加密技术及加密函数实战应用,覆盖MySQL、PostgreSQL、Oracle等主流数据库的20+生产级加密…