为什么Map.of不允许null键和值?
使用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); 
如果我们这样做,上述允许没有任何例外:
 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)的情况下java.util.Set.of("v1", "v2", null)发生同样的情况。 
 正如其他人指出的, Map合同允许零… 
[…] ome实现禁止
null键和值[…]。 尝试插入不合格的键或值将引发未检查的exception,通常为NullPointerException或ClassCastException。
…和收集工厂(不只是在地图上) 利用这一点 。
他们不允许
null键和值。 尝试使用null键或值创build它们会导致NullPointerException。
但为什么?
 在集合中允许null现在被视为devise错误。 这有很多原因。 好的一个是可用性,其中最突出的麻烦制造者是Map::get 。 如果它返回null ,则不清楚该键是否丢失或值为null 。 一般来说,保证null集合更易于使用。 实施方面,他们也需要较less的特殊shell,使代码更容易维护和更高性能。 
你可以听斯图尔特·马克斯在这个讲座中解释它,但是JEP 269 (引入工厂方法的那个)也总结了这一点:
空的元素,键和值将被禁止。 (最近没有引入的集合支持空值)。另外,禁止空值为更紧凑的内部表示提供了机会,更快的访问和更less的特殊情况。
 由于HashMap在慢慢发现的时候就已经出现了,现在修改它已经太晚了,而不会破坏现有的代码,但是这些接口的最新实现(例如ConcurrentHashMap )不再允许null ,并且工厂方法的新集合是没有例外。 
  (我还以为另一个原因是显式使用null值被认为是一个可能的实现错误,但我得到了错误,那就是要复制密钥,这也是非法的。) 
 因此,禁止null有一些技术上的原因,但是也使用创build的集合来提高代码的健壮性。 
 虽然HashMap确实允许空值,但Map.of不会使用HashMap并且如果使用key或value,则会引发exception,如文档所述 : 
Map.of()和Map.ofEntries()静态工厂方法提供了创build不可变映射的便捷方式。 这些方法创build的Map实例具有以下特征:
…
他们不允许null键和值。 尝试使用空键或值创build它们会导致NullPointerException。
 确切地说 – 一个HashMap被允许存储null, 而不是静态工厂方法返回的Map 。 并不是所有的地图都是一样的。 
 一般来说,据我所知,首先允许HashMap空值作为键是错误的,但新的集合禁止了这种可能性。 
 想象一下当你的HashMap中有一个具有特定键和值== null的Entry的情况。 你确实得到了,它返回null 。 这是什么意思? 它有一个null的映射或它不存在? 
  Key – 从这样一个空密钥的哈希代码必须特别对待所有的时间。 禁用空位开始 – 使这更容易。 
主要区别在于:当你build立你自己的地图的时候,你会隐含地说:“我想在我所做的事情上有充分的自由 ”。
所以,当你决定你的地图应该有一个空的键或值(可能是由于这里列出的原因),那么你可以自由地这样做。
但“选项2”是关于一个方便的东西 – 可能打算用于常量。 Java背后的人只是简单地决定:“当你使用这些方便的方法时,那么结果图就是无空的”。
允许空值意味着
  if (map.contains(key)) 
是不一样的
  if (map.get(key) != null) 
这有时可能是一个问题。 或者更确切地说:当处理那个非常地图的对象的时候,这是要记住的。
只是一个轶事暗示为什么这似乎是一个合理的方法:我们的团队自己实施类似的便利方法。 猜测一下:如果不知道关于未来Java标准方法的计划,我们的方法会做同样的事情:它们会返回一个不可变的传入数据副本; 当你提供null元素时,他们会抛出。 我们甚至非常严格,以至于当你通过空的名单/地图/ …我们也抱怨。
并非所有地图都允许null作为关键字
  docs of Map提到的原因。 
一些映射实现对它们可能包含的键和值有限制。 例如,一些实现禁止空键和值,一些实现对键的types有限制。 尝试插入不合格的键或值将引发未检查的exception,通常为NullPointerException或ClassCastException。
 在地图中允许空值是一个错误。  现在我们可以看到它了 ,但是我猜不知道HashMap何时被引入。  NullpointerException是生产代码中最常见的错误 。 
我可能会说JDK正在帮助开发者打击NPE瘟疫。 一些例子:
-   Optional介绍
-   Collectors.toMap(keyMapper, valueMapper)既不允许keyMapper也不允许valueMapper函数返回null值
-  如果find的值为null则Stream.findFirst()和Stream.findAny()抛出NPE
 所以,在新的JDK9不可变集合(和map)中不允许null只是沿着相同的方向。 我们都应该感谢它! 
 文档没有说明为什么不允许null : 
他们不允许
null键和值。 尝试使用null键或值创build它们会导致NullPointerException。
 在我看来, Map.of()和Map.ofEntries()静态工厂方法将产生一个常量,大多由开发人员在编译types中形成。 那么,为什么要保留null作为关键或价值呢? 
 然而, Map#put通常是通过在运行时填充一个映射来使用的,其中null键/值可能发生。