You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 6:基于POJO按服务/库名称分组统计状态数量方案咨询

解决方案

第一步:修正List的转换代码

你当前的循环存在严重问题:只创建了一个CampRepost对象,每次循环都覆盖它的属性,最终campRepostList里所有元素都是同一个对象的引用,数据全部被最后一次循环覆盖。必须把对象创建放到循环内部:

List<CampRepost> campRepostList = new ArrayList<>();

for (String line : values2) {
    // 先去除首尾空格,避免分割后出现空字符串或带空格的字段
    String trimmedLine = line.trim();
    String[] arrSplit = trimmedLine.split(",");
    
    CampRepost cmpRepost = new CampRepost(); // 每次循环创建新对象
    cmpRepost.setServiceName(arrSplit[0].trim());
    cmpRepost.setLibName(arrSplit[1].trim());
    cmpRepost.setVersion(arrSplit[2].trim());
    // 存储原始状态字符串的byte数组,后续统计时转成String处理
    cmpRepost.setStatus(arrSplit[3].trim().getBytes());
    
    campRepostList.add(cmpRepost);
}

第二步:定义状态归一化规则

你的数据里状态存在格式不一致(比如OverDue和Overdue、Due in <= 90和Due in <=90),需要先统一格式,避免统计错误。可以定义一个工具方法来归一化状态:

private static String normalizeStatus(byte[] statusBytes) {
    String status = new String(statusBytes).trim().toLowerCase();
    if (status.contains("overdue")) {
        return "Overdue";
    } else if (status.contains("<= 90") || status.contains("<=90")) {
        return "Due in <= 90";
    } else if (status.contains(">90")) {
        return "Due in >90";
    }
    return status; // 处理未知状态
}

第三步:实现分组统计(透视表逻辑)

可以用Java Stream API结合分组收集器来实现,核心思路是:

  1. 按指定字段(libName或serviceName)分组
  2. 对每组内的元素统计各状态的数量

方式1:自定义统计DTO(推荐)

先创建一个存储统计结果的类,让输出更清晰:

class StatusStatistics {
    private int dueLessEqual90 = 0;
    private int overdue = 0;
    private int dueGreater90 = 0;

    // 累加统计方法
    public void countStatus(String normalizedStatus) {
        switch (normalizedStatus) {
            case "Due in <= 90":
                dueLessEqual90++;
                break;
            case "Overdue":
                overdue++;
                break;
            case "Due in >90":
                dueGreater90++;
                break;
        }
    }

    // Getter方法,用于输出
    public int getDueLessEqual90() { return dueLessEqual90; }
    public int getOverdue() { return overdue; }
    public int getDueGreater90() { return dueGreater90; }
}

按libName分组统计

// 按libName分组,每组统计状态数量
Map<String, StatusStatistics> libStatsMap = campRepostList.stream()
    .collect(Collectors.groupingBy(
        CampRepost::getLibName,
        Collectors.collectingAndThen(
            Collectors.toList(),
            list -> {
                StatusStatistics stats = new StatusStatistics();
                list.forEach(camp -> {
                    String status = normalizeStatus(camp.getStatus());
                    stats.countStatus(status);
                });
                return stats;
            }
        )
    ));

// 输出报表
System.out.println("按libName分组统计:");
libStatsMap.forEach((libName, stats) -> {
    System.out.printf("libName: %s, Due in <= 90: %d, Overdue: %d, Due in >90: %d%n",
        libName, stats.getDueLessEqual90(), stats.getOverdue(), stats.getDueGreater90());
});

按serviceName分组统计

只需要修改分组的键为CampRepost::getServiceName即可:

Map<String, StatusStatistics> serviceStatsMap = campRepostList.stream()
    .collect(Collectors.groupingBy(
        CampRepost::getServiceName,
        Collectors.collectingAndThen(
            Collectors.toList(),
            list -> {
                StatusStatistics stats = new StatusStatistics();
                list.forEach(camp -> {
                    String status = normalizeStatus(camp.getStatus());
                    stats.countStatus(status);
                });
                return stats;
            }
        )
    ));

// 输出报表
System.out.println("\n按serviceName分组统计:");
serviceStatsMap.forEach((serviceName, stats) -> {
    System.out.printf("serviceName: %s, Due in <= 90: %d, Overdue: %d, Due in >90: %d%n",
        serviceName, stats.getDueLessEqual90(), stats.getOverdue(), stats.getDueGreater90());
});

方式2:用嵌套Map直接统计

如果不想创建DTO,可以用Map<String, Map<String, Integer>>来存储,外层键是分组字段,内层键是状态,值是数量:

// 按libName分组统计
Map<String, Map<String, Integer>> libStatsMap = campRepostList.stream()
    .collect(Collectors.groupingBy(
        CampRepost::getLibName,
        Collectors.toMap(
            camp -> normalizeStatus(camp.getStatus()),
            v -> 1,
            Integer::sum // 重复状态时累加数量
        )
    ));

// 输出时补全缺失的状态(数量为0)
System.out.println("按libName分组统计:");
libStatsMap.forEach((libName, statusMap) -> {
    int due90 = statusMap.getOrDefault("Due in <= 90", 0);
    int overdue = statusMap.getOrDefault("Overdue", 0);
    int dueGt90 = statusMap.getOrDefault("Due in >90", 0);
    System.out.printf("libName: %s, Due in <= 90: %d, Overdue: %d, Due in >90: %d%n",
        libName, due90, overdue, dueGt90);
});

关键注意事项

  • 状态归一化:必须处理数据中状态的大小写、空格差异,否则会出现统计遗漏
  • 对象创建位置:循环内必须每次创建新的CampRepost对象,否则列表数据会被覆盖
  • 空值/异常处理:如果values2中存在格式错误的行(比如分割后字段数不足4),需要添加判断逻辑避免数组越界

内容的提问来源于stack exchange,提问作者Selenium New bie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 07:27:33