Java 为什么 Map.of 不允许空键和值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/45210398/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does Map.of not allow null keys and values?
提问by hi.nitish
With Java 9, new factory methods have been introduced for the List
, Set
and Map
interfaces. These methods allow quickly instantiating a Map object with values in one line. Now, if we consider:
在 Java 9 中,为List
、Set
和Map
接口引入了新的工厂方法。这些方法允许使用一行中的值快速实例化 Map 对象。现在,如果我们考虑:
Map<Integer, String> map1 = new HashMap<Integer, String>(Map.of(1, "value1", 2, "value2", 3, "value3"));
map1.put(4, null);
The above is allowed without any exception while if we do:
以上是允许的,没有任何例外,而如果我们这样做:
Map<Integer, String> map2 = Map.of(1, "value1", 2, "value2", 3, "value3", 4, null );
It throws:
它抛出:
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:221)
..
I am not able to get, why null is not allowedin second case.
我无法得到,为什么在第二种情况下不允许 null。
I know HashMap can take null as a key as well as a value but why was that restricted in the case of Map.of?
我知道 HashMap 可以将 null 作为键和值,但为什么在 Map.of 的情况下会受到限制?
The same thing happens in the case of java.util.Set.of("v1", "v2", null)
and java.util.List.of("v1", "v2", null)
.
同样的事情发生在的情况下java.util.Set.of("v1", "v2", null)
和java.util.List.of("v1", "v2", null)
。
回答by Suresh Atta
Not all Maps allow null as key
并非所有 Map 都允许 null 作为键
The reason mentioned in the docs of Map
.
中提到的原因docs of Map
。
Some map implementations have restrictions on the keys and values they may contain. For example, some implementations prohibit null keys and values, and some have restrictions on the types of their keys. Attempting to insert an ineligible key or value throws an unchecked exception, typically NullPointerException or ClassCastException.
一些地图实现对它们可能包含的键和值有限制。例如,有些实现禁止空键和值,有些实现对其键的类型有限制。尝试插入不合格的键或值会引发未经检查的异常,通常为 NullPointerException 或 ClassCastException。
回答by Eugene
Exactly - a HashMap
is allowed to store null, notthe Map
returned by the static factory methods. Not allmaps are the same.
没错-一个HashMap
允许存储空,没有了Map
由静态工厂方法返回。并非所有地图都相同。
Generally as far as I know it has a mistake in the first place to allow nulls in the HashMap
as keys, newer collections ban that possibility to start with.
一般来说,据我所知,首先允许HashMap
as 键中的空值是错误的,较新的集合禁止这种可能性开始。
Think of the case when you have an Entry in your HashMap
that has a certain key and value == null. You do get, it returns null
. What does the mean? It has a mapping of null
or it is not present?
想想当您的条目中HashMap
有一个具有特定键和值 == 空的条目时的情况。你得到,它返回null
。这是什么意思?它有映射null
还是不存在?
Same goes for a Key
- hashcode from such a null key has to treated specially all the time. Banning nulls to start with - make this easier.
这同样适用于一个Key
-哈希码从这样的空键来专门处理所有的时间。禁止空值开始 - 让这更容易。
回答by 1615903
While HashMap does allow null values, Map.of
does not use a HashMap
and throws an exception if one is used either as key or value, as documented:
虽然 HashMap 确实允许空值,Map.of
但不使用 aHashMap
并在将一个用作键或值时抛出异常,如文档所示:
The Map.of() and Map.ofEntries() static factory methods provide a convenient way to create immutable maps. The Map instances created by these methods have the following characteristics:
...
They disallow null keys and values. Attempts to create them with null keys or values result in NullPointerException.
Map.of() 和 Map.ofEntries() 静态工厂方法提供了一种创建不可变映射的便捷方法。这些方法创建的 Map 实例具有以下特点:
...
它们不允许空键和值。尝试使用空键或值创建它们会导致 NullPointerException。
回答by Nicolai
As others pointed out, the Map
contractallows rejecting nulls...
正如其他人所指出的,在Map
合同允许拒绝空...
[S]ome implementations prohibit
null
keys and values [...]. Attempting to insert an ineligible key or value throws an unchecked exception, typicallyNullPointerException
orClassCastException
.
[S]某些实现禁止
null
键和值[...]。尝试插入不合格的键或值会引发未经检查的异常,通常为NullPointerException
或ClassCastException
。
... and the collection factories (not just on maps) make use of that.
...和收集工厂(不仅仅是在地图上)利用了那个。
They disallow
null
keys and values. Attempts to create them withnull
keys or values result inNullPointerException
.
它们不允许
null
键和值。尝试使用null
键或值创建它们会导致NullPointerException
.
But why?
但为什么?
Allowing null
in collections is by now seen as a design error. This has a variety of reasons. A good one is usability, where the most prominent trouble maker is Map::get
. If it returns null
, it is unclear whether the key is missing or the value was null
. Generally speaking, collections that are guaranteed null
free are easier to use. Implementation-wise, they also require less special casing, making the code easier to maintain and more performant.
null
现在允许集合被视为设计错误。这有多种原因。一个好的是可用性,其中最突出的麻烦制造者是Map::get
。如果返回null
,则不清楚是缺少键还是值是null
。一般来说,保证null
免费的集合更容易使用。在实现方面,它们还需要较少的特殊外壳,使代码更易于维护和性能更高。
You can listen to Stuart Marks explain it in this talkbut JEP 269(the one that introduced the factory methods) summarizes it as well:
你可以听 Stuart Marks在这个演讲中解释它,但JEP 269(介绍工厂方法的那个)也总结了它:
Null elements, keys, and values will be disallowed. (No recently introduced collections have supported nulls.) In addition, prohibiting nulls offers opportunities for a more compact internal representation, faster access, and fewer special cases.
将不允许使用空元素、键和值。(最近引入的集合都没有支持空值。)此外,禁止空值为更紧凑的内部表示、更快的访问和更少的特殊情况提供了机会。
Since HashMap
was already out in the wild when this was slowly discovered, it was too late to change it without breaking existing code but most recent implementations of those interfaces (e.g. ConcurrentHashMap
) do not allow null
anymore and the new collections for the factory methods are no exception.
由于HashMap
在慢慢发现时已经在野外,因此在不破坏现有代码的情况下对其进行更改为时已晚,但是这些接口的最新实现(例如ConcurrentHashMap
)不再允许null
,工厂方法的新集合也不例外。
(I thought another reason was that explicitly using null
values was seen as a likely implementation error but I got that wrong. That was about to duplicate keys, which are illegal as well.)
(我认为另一个原因是显式使用null
值被视为可能的实现错误,但我错了。这将复制密钥,这也是非法的。)
So disallowing null
had some technical reason but it was also done to improve the robustness of the code using the created collections.
所以禁止null
有一些技术原因,但这样做也是为了使用创建的集合来提高代码的健壮性。
回答by Andrew Tobilko
The documentation does not say whynull
is not allowed:
文档没有说明为什么null
不允许:
They disallow
null
keys and values. Attempts to create them withnull
keys or values result inNullPointerException
.
它们不允许
null
键和值。尝试使用null
键或值创建它们会导致NullPointerException
.
In my opinion, the Map.of()
and Map.ofEntries()
static factory methods, which are going to produce a constant, are mostly formed by a developer at the compile type. Then, what is the reason to keep a null
as the key or the value?
在我看来,将产生常量的Map.of()
和Map.ofEntries()
静态工厂方法主要由编译类型的开发人员形成。那么,保留 anull
作为键或值的原因是什么?
Whereas, the Map#put
is usually used by filling a map at runtime where null
keys/values could occur.
然而,Map#put
通常通过在运行时填充null
可能出现键/值的映射来使用。
回答by GhostCat
The major difference is: when you build your own Map the "option 1" way ... then you are implicitlysaying: "I want to have full freedomin what I am doing".
主要区别在于:当您以“选项 1”的方式构建自己的 Map 时……那么您就含蓄地说:“我希望在我正在做的事情上拥有完全的自由”。
So, when you decide that your map should have a null key or value (maybe for the reasons listed here) then you are free to do so.
因此,当您决定您的地图应该有一个空键或值(可能是出于此处列出的原因)时,您可以自由地这样做。
But "option 2" is about a convenience thing - probably intendedto be used for constants. And the people behind Java simply decided: "when you use these convenience methods, then the resulting map shall be null-free".
但是“选项 2”是关于方便的事情 - 可能旨在用于常量。Java 背后的人简单地决定:“当你使用这些方便的方法时,结果映射应该是空的”。
Allowing for null valuesmeans that
允许空值意味着
if (map.contains(key))
is not the same as
不一样
if (map.get(key) != null)
which might be a problem sometimes. Or more precisely: it is something to remember when dealing with that very map object.
有时这可能是一个问题。或者更准确地说:这是在处理那个地图对象时要记住的事情。
And just an anecdotal hint why this seems to be a reasonable approach: our team implemented similar convenience methods ourselves. And guess what: without knowing anything about plans about future Java standard methods - our methods do the exact same thing: they return an immutable copy of the incoming data; and they throw up when you provide null elements. We are even so strict that when you pass in emptylists/maps/... we complain as well.
这只是一个轶事提示,为什么这似乎是一种合理的方法:我们的团队自己实现了类似的便利方法。猜猜看:在对未来 Java 标准方法的计划一无所知的情况下 - 我们的方法做完全相同的事情:它们返回传入数据的不可变副本;当您提供 null 元素时,它们会抛出。我们甚至非常严格,当您传入空列表/地图/...时,我们也会抱怨。
回答by Federico Peralta Schaffner
Allowing nulls in maps has been an error. We can see it now, but I guess it wasn't clear when HashMap
was introduced. NullpointerException
is the most common bugseen in production code.
在地图中允许空值是一个错误。我们现在可以看到它,但我想不清楚何时HashMap
引入。NullpointerException
是生产代码中最常见的错误。
I would say that the JDK goes in the direction of helping developers fight the NPE plague. Some examples:
我会说 JDK 朝着帮助开发人员对抗 NPE 瘟疫的方向发展。一些例子:
- Introduction of
Optional
Collectors.toMap(keyMapper, valueMapper)
doesn't allow neither thekeyMapper
nor thevalueMapper
function to return anull
valueStream.findFirst()
andStream.findAny()
throw NPE if the value found isnull
- 介绍
Optional
Collectors.toMap(keyMapper, valueMapper)
不允许函数keyMapper
和valueMapper
函数返回null
值Stream.findFirst()
Stream.findAny()
如果找到的值是,则抛出 NPEnull
So, I think that disallowing null
in the new JDK9 immutable collections (and maps) goes in the same direction.
所以,我认为null
在新的 JDK9 不可变集合(和映射)中禁止是同一个方向。
回答by Pedro Borges
In my opinion non-nullability makes sense for keys, but not for values.
在我看来,不可空性对键有意义,但对值无效。
- The
Map
interface becomes a weak contract, you can't trust it's behaviour without looking at the implementation, and that is assuming you have access to see it. Java11'sMap.of()
does not allow null values whileHashMap
does, but they both implement the sameMap
contract - how come? - Having a null value or no value at all could not, and arguably should not be considered as a distinct scenario. When you get the value for a key and you get null, who cares if it was explicitly put there or not? there's simply no value for the supplied key, the map does not contain such key, simple as that.
- Existing libraries make extensive use of map as a means to pass properties to them, many of them optional, this makes
Map.of()
useless as a construct for such structures. - Kotlin enforces nullability at compile time and allows for maps with null values with no known issues.
- The reason behind not allowing null values is probably just due to implementation detail and convenience of the creator.
- 该
Map
接口变为弱合同,你不能没有看落实信任它的行为,这是假设你有机会看到它。Java11Map.of()
不允许空值HashMap
,但它们都实现了相同的Map
契约——怎么会呢? - 有一个空值或根本没有值是不可能的,并且可以说不应该被视为一个不同的场景。当你得到一个键的值并且你得到空值时,谁在乎它是否明确地放在那里?提供的键根本没有值,地图不包含这样的键,就这么简单。
- 现有的库广泛使用 map 作为向它们传递属性的一种手段,其中许多是可选的,这使得
Map.of()
作为此类结构的构造毫无用处。 - Kotlin 在编译时强制执行可空性,并允许使用没有已知问题的空值映射。
- 不允许空值背后的原因可能只是由于创建者的实现细节和便利性。