当前位置: 首页 > news >正文

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

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等收集器实现。

相关文章:

  • 八大经典排序算法
  • LeetCode:2595.奇偶位数
  • 云原生DevOps:Zadig架构设计与企业实践分析
  • 七星棋牌源码高阶技术指南:6端互通、200+子游戏玩法深度剖析与企业级搭建实战(完全开源)
  • 适用于复杂背景的YOLOv8改进:基于DCN的特征提取能力提升研究
  • Windows网络安全基础
  • 向 OpenAI ChatGPT 提问如何学习黑客
  • 硬盘识别不出来了怎么办?硬盘读不出来的解决方法
  • 基于Flask的租房信息可视化系统的设计与实现
  • 【项目实践06】【Retrofit2 框架的使用】
  • Linux-C/C++《C++/1、C++基础》(C++语言特性、面向对象等)
  • 【人工智能】用Python迈向轻量化深度学习——模型压缩与量化实战指南
  • 植物大战僵尸杂交版v3.2.1最新版本(附下载链接)
  • java简单实现请求deepseek
  • MySQL多列索引查询优化
  • express+Vue2进行项目实战-景点后台管理系统(上篇)
  • SpringCloud-Eureka初步使用
  • uniapp实现app的pdf预览
  • 手机控制电脑远程关机
  • SOC- armv8 启动流程和安全启动
  • 学做沪江网站要多久/网站买卖
  • 网站设计的基本方法/苏州网站建设制作公司
  • 网站模板文件扫描/郑州网站seo推广
  • 网站升级正在升级维护/百度推广营销方案
  • 数字展厅公司排名/网站排名优化培训
  • 做印刷的网站/怎样搭建网站