在 Java 9 中,为 List
、Set
和 Map
接口(interface)引入了新的工厂方法。这些方法允许使用一行中的值快速实例化 Map 对象。现在,如果我们考虑:
Map<Integer, String> map1 = new HashMap<Integer, String>(Map.of(1, "value1", 2, "value2", 3, "value3"));
map1.put(4, null);
如果我们这样做,则无一异常(exception)地允许上述情况:
Map<Integer, String> map2 = Map.of(1, "value1", 2, "value2", 3, "value3", 4, null );
它抛出:
Exception in thread "main" java.lang.NullPointerException
at java.base/java.util.Objects.requireNonNull(Objects.java:221)
..
我无法得到,为什么在第二种情况下不允许使用 null。
我知道 HashMap 可以将 null 作为键和值,但为什么在 Map.of 的情况下会受到限制?
同样的事情发生在 java.util.Set.of("v1", "v2", null)
和 java.util.List.of("v1 ", "v2", null)
.
最佳答案
正如其他人指出的那样,the Map
contract允许拒绝空值...
[S]ome implementations prohibit
null
keys and values [...]. Attempting to insert an ineligible key or value throws an unchecked exception, typicallyNullPointerException
orClassCastException
.
...和收集工厂(不只是在 map 上)make use of that .
They disallow
null
keys and values. Attempts to create them withnull
keys or values result inNullPointerException
.
但是为什么呢?
在集合中允许 null
现在被视为设计错误。这有多种原因。一个好的是可用性,其中最突出的麻烦制造者是 Map::get
。如果它返回 null
,则不清楚是缺少键还是值是 null
。一般来说,保证 null
免费的集合更容易使用。在实现方面,它们还需要较少的特殊大小写,从而使代码更易于维护且性能更高。
你可以听 Stuart Marks 解释 in this talk但是 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.
由于 HashMap
在慢慢被发现时已经被广泛使用,因此在不破坏现有代码的情况下更改它为时已晚,但这些接口(interface)的最新实现(例如 ConcurrentHashMap
)没有不再允许null
,工厂方法的新集合也不异常(exception)。
(我认为另一个原因是显式使用 null
值被视为可能的实现错误,但我错了。那是要复制键,这也是非法的。)
所以不允许 null
有一些技术原因,但这样做也是为了提高使用创建的集合的代码的健壮性。
关于java - 为什么 Map.of 不允许空键和值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45210398/