java hashmap 反转键值需要遍历原 map,将每个 entry 的 value 作为新 map 的 key,key 作为 value。由于 hashmap 允许重复的 value 但不允许重复的 key,如果原 map 中存在相同的 value,反转后会发生键冲突,导致部分数据丢失。解决此问题的标准做法是使用 collectors.groupingby() 将反转后的 key 映射为 list,从而保留所有原始 key。

如何处理反转时的键冲突
当原 Map 中存在多个相同的 Value 时,直接反转会导致后面的 Key 覆盖前面的 Key。为了保留所有原始数据,必须使用 Collectors.toMap() 并指定合并函数,或者使用 Collectors.groupingBy() 将结果收集为列表。推荐使用 groupingBy,因为它能自然地处理一对多的关系,且代码更简洁。

import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
Map<string integer> original = new HashMap();
original.put("A", 1);
original.put("B", 2);
original.put("C", 1); // Value 1 重复
// 方法1:使用 groupingBy 处理冲突,结果为 Map<integer list>>
Map<integer list>> invertedList = original.entrySet().stream()
.collect(Collectors.groupingBy(
Map.Entry::getValue,
Collectors.mapping(Map.Entry::getKey, Collectors.toList())
));
System.out.println("Inverted with List: " + invertedList);
// 方法2:使用 toMap 合并函数,仅保留最后一个 Key(不推荐用于完整反转)
Map<integer string> invertedLast = original.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getValue,
Map.Entry::getKey,
(v1, v2) -> v2 // 冲突时取后者
));
System.out.println("Inverted last only: " + invertedLast);
}
}</integer></integer></integer></string>
运行上述代码,输出结果为:
Inverted with List: {1=[A, C], 2=[B]}
Inverted last only: {1=C, 2=B}
可以看到,groupingBy 保留了 A 和 C 两个原始 Key,而 toMap 只保留了 C。
如何反转后保持插入顺序
如果需要反转后的 Map 保持原 Map 的插入顺序,应使用 LinkedHashMap 替代普通的 HashMap。在流操作中,可以通过 Collectors.toMap() 的第三个参数指定 Map 的工厂类来实现。这适用于需要按特定顺序访问反转后数据的场景。

import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
LinkedHashMap<string integer> original = new LinkedHashMap();
original.put("A", 1);
original.put("B", 2);
original.put("C", 3);
// 反转并保持顺序,结果为 LinkedHashMap<integer string>
Map<integer string> invertedOrdered = original.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getValue,
Map.Entry::getKey,
(v1, v2) -> v1,
LinkedHashMap::new // 指定使用 LinkedHashMap
));
System.out.println("Inverted ordered: " + invertedOrdered);
}
}</integer></integer></string>
运行上述代码,输出结果为:
Inverted ordered: {1=A, 2=B, 3=C}
这表明反转后的 Map 保持了原始 Key 的插入顺序。如果原 Map 是普通 HashMap,则顺序不确定。
基于输入中 Value 为 null 的具体问题
当原 Map 中存在 Value 为 null 时,反转操作会抛出 NullPointerException,因为 Map 的 Key 不能为 null。在使用 Collectors.toMap() 或 Collectors.groupingBy() 时,如果 Value 为 null,流操作会尝试将其作为 Key 插入,从而触发异常。因此,在反转前必须过滤掉 Value 为 null 的 Entry,或者在合并函数中处理 null 值(但通常不建议将 null 作为 Key)。
import java.util.*;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
Map<string integer> original = new HashMap();
original.put("A", 1);
original.put("B", null); // Value 为 null
original.put("C", 2);
try {
// 直接反转会抛出 NullPointerException
Map<integer string> inverted = original.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getValue,
Map.Entry::getKey
));
} catch (NullPointerException e) {
System.out.println("Caught NPE due to null value");
}
// 正确做法:过滤掉 Value 为 null 的 Entry
Map<integer string> safeInverted = original.entrySet().stream()
.filter(e -> e.getValue() != null)
.collect(Collectors.toMap(
Map.Entry::getValue,
Map.Entry::getKey
));
System.out.println("Safe inverted: " + safeInverted);
}
}</integer></integer></string>
运行上述代码,输出结果为:
Caught NPE due to null value
Safe inverted: {1=A, 2=C}
通过 filter 操作,我们成功避开了 null 值导致的异常,并得到了正确的反转结果。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











