合并操作中的 HashMap 空检查
HashMap null check in Merge Operation
为什么 HashMap 合并要对值进行空值检查。 HashMap 支持 null 键和 null values.So 有人可以告诉我为什么需要对合并进行 null 检查吗?
@Override
public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
if (value == null)
throw new NullPointerException();
if (remappingFunction == null)
throw new NullPointerException();
因此,我无法使用 Collectors.toMap(Function.identity(), this::get)
在地图
中收集值
因为 内部 用于 Collectors.toMap
,所以使用了 Map#merge
- 你真的无能为力。使用静态 Collectors.toMap
不是一个选项(顺便说一下,它被记录为抛出 NullPointerException
)。
但是旋转一个自定义收集器来做你想做的事情(你没有展示)并不那么复杂,这里有一个例子:
Map<Integer, Integer> result = Arrays.asList(null, 1, 2, 3)
.stream()
.collect(
HashMap::new,
(map, i) -> {
map.put(i, i);
},
HashMap::putAll);
该行为由 the Map.merge
contract 强制执行:
Throws:
…
NullPointerException - if the specified key is null and this map does not support null keys or the value or remappingFunction is null
请注意,将 Map.merge
用于 Collectors.toMap
without a merge function 是一个实现细节;它不仅不允许 null
值,也没有提供报告重复键所需的行为,Java 8 实现在存在重复键时错误地将两个值之一报告为键。
在 Java 9 中,实现已完全重写,不再使用 Map.merge
。但是新的实现是行为兼容的,现在有代码在值为 null
时显式抛出。因此 Collectors.toMap
不接受 null
值的行为已在代码中修复,不再是使用 Map.merge
的产物。 (还是只说 toMap
没有合并功能的收集器。)
可惜,the documentation没说。
作为 toMap
和 merge
中提到的空值问题的解决方法
您可以尝试通过以下方式使用自定义收集器:
public static <T, R> Map<T, R> mergeTwoMaps(final Map<T, R> map1,
final Map<T, R> map2,
final BinaryOperator<R> mergeFunction) {
return Stream.of(map1, map2).flatMap(map -> map.entrySet().stream())
.collect(HashMap::new,
(accumulator, entry) -> {
R value = accumulator.containsKey(entry.getKey())
? mergeFunction.apply(accumulator.get(entry.getKey()), entry.getValue())
: entry.getValue();
accumulator.put(entry.getKey(), value);
},
HashMap::putAll);
}
为什么 HashMap 合并要对值进行空值检查。 HashMap 支持 null 键和 null values.So 有人可以告诉我为什么需要对合并进行 null 检查吗?
@Override
public V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
if (value == null)
throw new NullPointerException();
if (remappingFunction == null)
throw new NullPointerException();
因此,我无法使用 Collectors.toMap(Function.identity(), this::get)
在地图
因为 内部 用于 Collectors.toMap
,所以使用了 Map#merge
- 你真的无能为力。使用静态 Collectors.toMap
不是一个选项(顺便说一下,它被记录为抛出 NullPointerException
)。
但是旋转一个自定义收集器来做你想做的事情(你没有展示)并不那么复杂,这里有一个例子:
Map<Integer, Integer> result = Arrays.asList(null, 1, 2, 3)
.stream()
.collect(
HashMap::new,
(map, i) -> {
map.put(i, i);
},
HashMap::putAll);
该行为由 the Map.merge
contract 强制执行:
Throws:
…
NullPointerException - if the specified key is null and this map does not support null keys or the value or remappingFunction is null
请注意,将 Map.merge
用于 Collectors.toMap
without a merge function 是一个实现细节;它不仅不允许 null
值,也没有提供报告重复键所需的行为,Java 8 实现在存在重复键时错误地将两个值之一报告为键。
在 Java 9 中,实现已完全重写,不再使用 Map.merge
。但是新的实现是行为兼容的,现在有代码在值为 null
时显式抛出。因此 Collectors.toMap
不接受 null
值的行为已在代码中修复,不再是使用 Map.merge
的产物。 (还是只说 toMap
没有合并功能的收集器。)
可惜,the documentation没说。
作为 toMap
和 merge
中提到的空值问题的解决方法
您可以尝试通过以下方式使用自定义收集器:
public static <T, R> Map<T, R> mergeTwoMaps(final Map<T, R> map1,
final Map<T, R> map2,
final BinaryOperator<R> mergeFunction) {
return Stream.of(map1, map2).flatMap(map -> map.entrySet().stream())
.collect(HashMap::new,
(accumulator, entry) -> {
R value = accumulator.containsKey(entry.getKey())
? mergeFunction.apply(accumulator.get(entry.getKey()), entry.getValue())
: entry.getValue();
accumulator.put(entry.getKey(), value);
},
HashMap::putAll);
}