讲师中心 微信公众号
AI工具推荐 视频效率加速

Java 8:如何收集Map中所有具有相同最大值的键列表

夜宇姑娘_7445

夜宇姑娘_7445

发布时间:2025-09-22 17:26:01

|

608人浏览过

|

来源于php中文网

原创

Java 8:如何收集Map中所有具有相同最大值的键列表

本教程旨在解决一个常见的数据处理问题:从一个Map<String, Integer>中,提取所有与最大整数值相关联的键(String)。特别地,当多个键共享同一个最大值时,我们期望能够收集到所有这些键的列表。

问题描述

假设我们有一个map<string, integer>,其中包含键值对。我们的目标是找到所有值等于map中最大值的键。

示例Map:

final Map<String, Integer> map = new HashMap<>();
map.put("first", 50);
map.put("second", 10);
map.put("third", 50);
map.put("fourth", 20);

对于上述示例,Map中的最大值是50。键"first"和"third"都对应这个最大值。因此,我们期望的输出是一个包含["first", "third"]的列表。

现有尝试的局限性:

直接使用stream().max(Map.Entry.comparingByValue()).map(Map.Entry::getKey)通常只能返回一个键,即使存在多个键拥有相同的最大值。例如,它可能返回"third"(取决于流的内部顺序),但会忽略"first"。这不符合我们收集所有最大值键的需求。

立即学习“Java免费学习笔记(深入)”;

解决方案一:使用Java 8 Stream API

此方法利用Java 8的Stream API进行多步处理。核心思想是首先根据值对Map的条目进行分组,然后从这些分组中找出与最大值对应的键列表。

实现思路:

  1. 将Map.Entry流转换为Map<Integer, List<String>>,其中键是原始Map中的值,而值是所有对应这些值的键的列表。
  2. 从这个新的Map中,找到键(即原始值)最大的那个条目。
  3. 提取该条目中的值(即我们需要的键列表)。

代码示例:

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

import static java.util.stream.Collectors.*;

public class MaxKeysCollector {

    public static List<String> getMaxKeysUsingStream(Map<String, Integer> map) {
        return map.entrySet()
                .stream()
                // 步骤1: 按值分组。键是原始值,值是所有对应这些值的键的列表。
                // 例如: {50=[first, third], 10=[second], 20=[fourth]}
                .collect(groupingBy(Map.Entry::getValue, mapping(Map.Entry::getKey, toList())))
                .entrySet()
                .stream()
                // 步骤2: 找出新Map中键(即原始最大值)最大的条目。
                .max(Map.Entry.<Integer, List<String>>comparingByKey())
                // 步骤3: 获取该条目的值,即包含所有最大值键的列表。
                .orElseThrow(() -> new IllegalStateException("Map cannot be empty to find max keys."))
                .getValue();
    }

    public static void main(String[] args) {
        final Map<String, Integer> map = new HashMap<>();
        map.put("first", 50);
        map.put("second", 10);
        map.put("third", 50);
        map.put("fourth", 20);

        List<String> maxKeys = getMaxKeysUsingStream(map);
        System.out.println("Stream API 方法获取的最大值键列表: " + maxKeys); // 预期输出: [first, third] 或 [third, first] (顺序不保证)
    }
}

代码解析:

  • groupingBy(Map.Entry::getValue, mapping(Map.Entry::getKey, toList())):这是核心操作。它首先将Map的条目按照它们的值(Map.Entry::getValue)进行分组。对于每个分组,它不是简单地收集Map.Entry,而是通过mapping(Map.Entry::getKey, toList())进一步处理,只收集键并将其放入一个列表中。
  • max(Map.Entry.<Integer, List<String>>comparingByKey()):在生成的新Map(Map<Integer, List<String>>)上,我们再次创建一个流,并使用max操作符,通过比较键(即原始Map中的值)来找到最大的条目。
  • orElseThrow().getValue():如果Map不为空,max操作会返回一个Optional<Map.Entry<Integer, List<String>>>。orElseThrow()用于获取其内部值,然后getValue()提取出该条目中包含的键列表。

注意事项:

Java Maven Code Review
Java Maven Code Review

审查Java Maven项目(ZIP压缩包或GitLab仓库URL),检查代码规范、命名、模块边界、可维护性问题以及重复代码。

下载

此方法涉及两次流迭代。第一次迭代用于分组,第二次迭代用于查找最大分组。虽然第二次迭代的Map通常会比原始Map小,但在数据量非常大的情况下,这可能会带来一定的性能开销。

解决方案二:单次迭代的命令式循环

对于追求极致性能的场景,一个传统的命令式循环通常是最高效的解决方案,因为它只需要对Map进行一次遍历。

实现思路:

  1. 初始化一个空列表maxKeys来存储结果。
  2. 初始化maxValue为Integer.MIN_VALUE,用于跟踪当前遇到的最大值。
  3. 遍历Map的每个条目。
  4. 对于每个条目:
    • 如果当前条目的值小于maxValue,则跳过(它不可能是最大值)。
    • 如果当前条目的值大于maxValue,说明我们找到了一个新的最大值。此时,需要清空maxKeys列表,因为之前收集的键不再是最大值对应的键。
    • 更新maxValue为当前条目的值。
    • 将当前条目的键添加到maxKeys列表中。

代码示例:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MaxKeysCollector {

    public static List<String> getMaxKeysUsingLoop(Map<String, Integer> map) {
        List<String> maxKeys = new ArrayList<>();
        int maxValue = Integer.MIN_VALUE; // 初始化为最小值

        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            int currentValue = entry.getValue();
            String currentKey = entry.getKey();

            if (currentValue < maxValue) {
                // 当前值小于已知的最大值,跳过
                continue;
            }

            if (currentValue > maxValue) {
                // 找到了一个新的最大值,清空之前收集的键
                maxKeys.clear();
                maxValue = currentValue; // 更新最大值
            }
            // 如果 currentValue == maxValue,或者 currentValue > maxValue (清空后),则添加当前键
            maxKeys.add(currentKey);
        }
        return maxKeys;
    }

    public static void main(String[] args) {
        final Map<String, Integer> map = new HashMap<>();
        map.put("first", 50);
        map.put("second", 10);
        map.put("third", 50);
        map.put("fourth", 20);
        map.put("fifth", 60); // 添加一个更大的值测试

        List<String> maxKeysLoop = getMaxKeysUsingLoop(map);
        System.out.println("命令式循环方法获取的最大值键列表: " + maxKeysLoop); // 预期输出: [fifth]

        final Map<String, Integer> map2 = new HashMap<>();
        map2.put("first", 50);
        map2.put("second", 10);
        map2.put("third", 50);
        List<String> maxKeysLoop2 = getMaxKeysUsingLoop(map2);
        System.out.println("命令式循环方法获取的最大值键列表 (原始示例): " + maxKeysLoop2); // 预期输出: [first, third]
    }
}

代码解析:

  • maxValue = Integer.MIN_VALUE;:确保任何Map中的值都能被正确识别为大于或等于初始最大值。
  • if (currentValue < maxValue) continue;:这是一个优化,如果当前值明显小于已知的最大值,则无需进行后续操作,直接进入下一个条目。
  • if (currentValue > maxValue) maxKeys.clear();:这是关键逻辑。当发现一个比当前maxValue更大的值时,意味着之前maxKeys中收集的所有键都不再是最大值对应的键了,因此需要清空列表。
  • maxValue = currentValue;:更新maxValue为新的最大值。
  • maxKeys.add(currentKey);:将当前键添加到maxKeys中。这个操作会在两种情况下发生:
    • currentValue等于maxValue(收集所有相同最大值的键)。
    • currentValue大于maxValue(在清空列表并更新maxValue之后,将新最大值对应的键添加进去)。

性能优势:

此方法只需要对Map进行一次迭代,因此在性能上通常优于Stream API的多步处理方法,尤其是在Map包含大量数据时。

总结与选择

本文提供了两种在Java 8中收集Map中所有具有相同最大值的键列表的方法:

  1. Stream API方法: 简洁、声明性强,利用了groupingBy和max等高级Stream操作。代码可读性较高,但涉及多次迭代,可能在极端性能要求下略逊一筹。
  2. 命令式循环方法: 性能最优,仅需单次迭代。逻辑清晰,易于理解其执行过程,适用于对性能有严格要求的场景。

在实际开发中,如果Map的数据量不是特别巨大,Stream API方法因其简洁性和声明性通常是更受欢迎的选择。但如果Map可能包含数十万甚至数百万条目,并且性能是首要考虑因素,那么单次迭代的命令式循环将是更明智的选择。

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

5799

2023.08.02

java break和continue
java break和continue

本专题整合了java break和continue的区别相关内容,阅读专题下面的文章了解更多详细内容。

727

2025.10.24

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

510

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

323

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

513

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

263

2025.11.27

FrankenPHP集成Laravel详细教程
FrankenPHP集成Laravel详细教程

本专题提供FrankenPHP集成Laravel的详细配置指南,全面解析运行原理、开发环境搭建、Caddyfile配置、Octane工作模式、数据库连接、队列任务、定时任务和生产环境优化,解决部署过程中常见的报错与兼容性问题。

0

2026.10.08

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

120

2026.09.30

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

100

2026.09.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
dev.java 官方:Learn Java
dev.java 官方:Learn Java

共0课时 | 0人学习

Java JDBC数据库连接官方教程
Java JDBC数据库连接官方教程

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn