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

如何使用Java 8 Stream按周分组LocalDate-Integer映射并获取每周最大值(含异常问题咨询)

解决Java Stream按周分组并取每周最大值的问题

我来帮你搞定这个按周分组取最大值的需求,先拆解下你遇到的几个痛点,再给出可行的解决方案,顺便解释下你原来代码出错的原因。

为什么你的代码会报错?

你原来的代码里用了w/M/YY来格式化日期,然后再解析回LocalDate,这里的核心问题是**YY代表的是“基于周的年份”(Week-based Year),而M是实际的月份**,这两个字段经常会出现冲突:比如某个日期属于2020年的第5周,但实际月份是2月,而基于周的年份第5周对应的月份可能是1月,解析器就会抛出你看到的月份不匹配异常。这种通过字符串格式化再解析的方式既麻烦又容易出错,完全没必要。

正确的解决方案思路

要解决所有痛点,关键是要生成唯一且可排序的周标识:

  • 不能只用周数,必须带上年份(或者基于周的年份),避免不同年份的周混淆;
  • 分组键要支持自然排序,方便TreeMap自动排序;
  • 尽量直接操作LocalDate,避免字符串解析的麻烦。

下面给你两种实用的实现方案:


方案1:用每周的起始日期作为分组键(推荐)

把每个日期映射到该周的起始日期(比如周一,你也可以改成周日),用这个起始日期作为分组键。这样既直观,又能利用LocalDate的可排序性让TreeMap自动排序,还完全避免了字符串解析的问题。

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class WeekGroupingExample {

    // 获取某日期所在周的周一作为起始日期(可根据需求改成周日)
    private static LocalDate getWeekStartDate(LocalDate date) {
        return date.with(DayOfWeek.MONDAY);
    }

    public static Map<LocalDate, Integer> maxByWeek(Map<LocalDate, Integer> dateValueMap) {
        return dateValueMap.entrySet().stream()
                .collect(Collectors.groupingBy(
                        // 按每周起始日期分组
                        entry -> getWeekStartDate(entry.getKey()),
                        // 用TreeMap保证按键自然排序
                        TreeMap::new,
                        // 计算每组的最大值
                        Collectors.reducing(0, Map.Entry::getValue, Math::max)
                ));
    }

    // 测试你的数据集
    public static void main(String[] args) {
        // 你的数据集初始化(保持你原有的代码即可)
        Map<LocalDate,Integer> cumulativeGarbageWasteDate = ...;
        
        Map<LocalDate, Integer> result = maxByWeek(cumulativeGarbageWasteDate);
        result.forEach((weekStart, maxValue) -> 
            System.out.printf("周起始日期:%s,最大值:%d%n", weekStart, maxValue));
    }
}

这个方案完美解决你的所有痛点:

  • 不需要将字符串转回LocalDate,直接用原键的LocalDate生成分组键;
  • TreeMap可以直接对LocalDate进行自然排序;
  • 每周起始日期包含完整的年份和日期,不会出现跨年份周重叠的问题;
  • 不同年份的周会被清晰区分(比如2020年第18周和2021年第18周的起始日期完全不同)。

方案2:用“年份-周数”字符串作为分组键

如果你更倾向于用类似2020-W05这样的字符串标识一周,也可以用基于周的年份+周数来生成键,TreeMap同样能对这种字符串进行自然排序:

import java.time.LocalDate;
import java.time.temporal.IsoFields;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;

public class WeekGroupingExample {

    public static Map<String, Integer> maxByWeekUsingYearWeekString(Map<LocalDate, Integer> dateValueMap) {
        return dateValueMap.entrySet().stream()
                .collect(Collectors.groupingBy(
                        entry -> {
                            LocalDate date = entry.getKey();
                            // 获取基于周的年份(避免跨年周的年份混乱)
                            int weekYear = date.get(IsoFields.WEEK_BASED_YEAR);
                            // 获取该年份下的周数
                            int weekOfYear = date.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
                            // 格式化为"YYYY-WWW"的字符串,比如2020-W05
                            return String.format("%d-W%02d", weekYear, weekOfYear);
                        },
                        TreeMap::new,
                        Collectors.reducing(0, Map.Entry::getValue, Math::max)
                ));
    }
}

这个方案的优势是键的可读性更强,直接能看到是哪一年的第几周,同样能解决所有痛点。


验证你的测试数据

用你的数据集测试的话,比如2021年1月1日-3日,如果周起始定义为周一,这几天会属于2020年的第53周(2020年12月28日是周一),而1月6日周三属于2021年第2周,分组会正确区分,最大值也会被正确计算。

内容的提问来源于stack exchange,提问作者dancisdoted d

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 21:32:37