Java 9では、List
、Set
、およびMap
インターフェイス用の新しいファクトリメソッドが導入されました。これらのメソッドにより、Mapオブジェクトを1行の値ですばやくインスタンス化できます。今、私たちが考慮した場合:
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が許可されないのか 2番目の場合。
HashMapはキーとしても値としてもnullを使用できることを知っていますが、Map.ofの場合はなぜ制限されているのですか?
Java.util.Set.of("v1", "v2", null)
とJava.util.List.of("v1", "v2", null)
の場合にも同じことが起こります。
他の人が指摘したように、 Map
コントラクト はnullを拒否できます...
[S]一部の実装では、
null
キーと値[...]が禁止されています。不適格なキーまたは値を挿入しようとすると、通常NullPointerException
またはClassCastException
のような未チェックの例外がスローされます。
...およびコレクションファクトリ(マップ上だけでなく) それを利用する 。
null
キーと値は許可されません。null
キーまたは値を使用してそれらを作成しようとすると、NullPointerException
になります。
コレクションでnull
を許可することは、設計エラーと見なされるようになりました。これにはさまざまな理由があります。優れたものは使いやすさで、最も顕著なトラブルメーカーはMap::get
です。 null
を返す場合、キーが欠落しているか、値がnull
であったかは不明です。一般的に、null
が無料であることが保証されているコレクションは使いやすいです。実装面では、特別なケーシングも必要ないため、コードの保守が容易になり、パフォーマンスが向上します。
Stuart Marksの説明を聞くことができます このトークで ですが JEP 269 (ファクトリーメソッドを導入したもの)でも要約しています
Null要素、キー、および値は許可されません。 (最近導入されたコレクションはnullをサポートしていません。)さらに、nullを禁止すると、内部表現がよりコンパクトになり、アクセスが速くなり、特殊なケースが少なくなります。
これがゆっくりと発見されたときにHashMap
がすでに公開されていたため、既存のコードを壊さずに変更するには遅すぎましたが、それらのインターフェイスの最新の実装(たとえば ConcurrentHashMap
)ではnull
が許可されなくなり、ファクトリメソッドの新しいコレクションも例外ではありません。
(別の理由は、null
値を明示的に使用することは実装エラーの可能性が高いと考えられていたが、間違っていたためだと考えました。
したがって、null
を許可しないことには技術的な理由がありますが、作成されたコレクションを使用してコードの堅牢性を向上させるためにも行われました。
正確に-HashMap
はnullの格納が許可されています。not静的ファクトリメソッドによって返されるMap
。 allマップは同じではありません。
一般的に、私が知る限り、最初の場所でHashMap
にnullをキーとして許可するのに誤りがあるため、新しいコレクションは最初からその可能性を禁止しています。
特定のキーと値== nullを持つHashMap
にエントリがある場合を考えてください。取得します。null
を返します。どういう意味ですか? null
のマッピングがあるか、存在しませんか?
Key
についても同様です。このようなnullキーからのハッシュコードは常に特別に処理する必要があります。最初からヌルを禁止-これを簡単にします。
HashMapはnull値を許可しますが、Map.of
はHashMap
を使用せず、キーまたは値のいずれかとして使用される場合、 documented のように例外をスローします。
Map.of()およびMap.ofEntries()静的ファクトリメソッドは、不変のマップを作成する便利な方法を提供します。これらのメソッドによって作成されたMapインスタンスには、次の特性があります。
...
Nullキーと値は許可されません。 NULLキーまたは値を使用してそれらを作成しようとすると、NullPointerExceptionが発生します。
マップでヌルを許可するとエラーになります。見ることができますnowが、HashMap
がいつ導入されたかは明らかではなかったと思います。 NullpointerException
は、実稼働コードで見られる 最も一般的なバグ です。
JDKは、開発者がNPEペストと戦うのを支援する方向に向かっていると言えるかもしれません。いくつかの例:
Optional
の紹介Collectors.toMap(keyMapper, valueMapper)
は、keyMapper
関数もvalueMapper
関数もnull
値を返すことを許可しませんStream.findFirst()
およびStream.findAny()
は、見つかった値がnull
の場合にNPEをスローしますそのため、新しいJDK9不変コレクション(およびマップ)でnull
を禁止すると、同じ方向に進みます。そして、私たち全員に感謝する必要があります!
主な違いは、「オプション1」の方法で独自のマップを作成する場合... 暗黙的にと言うことです:「完全な自由が欲しい私がやっていること」。
したがって、マップにnullキーまたはnull値が必要であると判断した場合(おそらく here にリストされている理由のため)、自由に行うことができます。
しかし、「オプション2」は便利さに関するものです-おそらく intended が定数に使用されます。そして、Javaの背後にいる人々は、単に「これらの便利なメソッドを使用する場合、結果のマップにはnullがないこと」を決定しました。
Null values を許可すると、
if (map.contains(key))
とは異なります
if (map.get(key) != null)
時々問題になるかもしれません。もっと正確に言うと、まさにそのマップオブジェクトを扱うときに覚えておくべきものです。
そして、これが合理的なアプローチであると思われる理由の単なる逸話のヒントです。私たちのチームは同様の便利な方法を自分たちで実装しました。そして、次のことを推測してください。将来のJava標準メソッドに関する計画について何も知らずに-私たちのメソッドはまったく同じことを行います。これらは、着信データの不変のコピーを返します。また、null要素を指定するとスローされます。あなたが empty lists/maps/...を渡すと、私たちも文句を言うほど厳格です。
すべてのマップがキーとしてnullを許可するわけではありません
docs of Map
に記載されている理由。
一部のマップ実装には、含まれるキーと値に制限があります。たとえば、一部の実装ではヌルのキーと値が禁止されており、一部の実装ではキーのタイプに制限があります。不適格なキーまたは値を挿入しようとすると、未チェックの例外、通常はNullPointerExceptionまたはClassCastExceptionがスローされます。
ドキュメントにはwhynull
は許可されていませんと書かれていません。
null
キーと値を許可しません。null
キーまたは値でそれらを作成しようとすると、NullPointerException
になります。
私の意見では、定数を生成するMap.of()
およびMap.ofEntries()
静的ファクトリーメソッドは、ほとんどがコンパイルタイプの開発者によって形成されます。次に、null
をキーまたは値として保持する理由は何ですか?
一方、Map#put
は通常、実行時にnull
キー/値が発生する可能性のあるマップを埋めるために使用されます。