0

0

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

DDD

DDD

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

|

588人浏览过

|

来源于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()提取出该条目中包含的键列表。

注意事项:

零沫AI工具导航
零沫AI工具导航

零沫AI工具导航-AI导航新标杆,探索全球实用AI工具

下载

此方法涉及两次流迭代。第一次迭代用于分组,第二次迭代用于查找最大分组。虽然第二次迭代的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

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
string转int
string转int

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

1031

2023.08.02

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

847

2023.08.22

java break和continue
java break和continue

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

261

2025.10.24

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

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

77

2025.09.05

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

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

40

2025.11.16

golang map原理
golang map原理

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

67

2025.11.17

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

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

47

2025.11.27

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

37

2026.03.12

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

136

2026.03.11

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.4万人学习

C# 教程
C# 教程

共94课时 | 11.3万人学习

Java 教程
Java 教程

共578课时 | 81.5万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号