web-dev-qa-db-ja.com

Map.ofがnullキーと値を許可しないのはなぜですか?

Java 9では、ListSet、および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)の場合にも同じことが起こります。

57
hi.nitish

他の人が指摘したように、 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を許可しないことには技術的な理由がありますが、作成されたコレクションを使用してコードの堅牢性を向上させるためにも行われました。

64
Nicolai

正確に-HashMapはnullの格納が許可されています。not静的ファクトリメソッドによって返されるMapallマップは同じではありません。

一般的に、私が知る限り、最初の場所でHashMapにnullをキーとして許可するのに誤りがあるため、新しいコレクションは最初からその可能性を禁止しています。

特定のキーと値== nullを持つHashMapにエントリがある場合を考えてください。取得します。nullを返します。どういう意味ですか? nullのマッピングがあるか、存在しませんか?

Keyについても同様です。このようなnullキーからのハッシュコードは常に特別に処理する必要があります。最初からヌルを禁止-これを簡単にします。

10
Eugene

HashMapはnull値を許可しますが、Map.ofHashMapを使用せず、キーまたは値のいずれかとして使用される場合、 documented のように例外をスローします。

Map.of()およびMap.ofEntries()静的ファクトリメソッドは、不変のマップを作成する便利な方法を提供します。これらのメソッドによって作成されたMapインスタンスには、次の特性があります。

  • ...

  • Nullキーと値は許可されません。 NULLキーまたは値を使用してそれらを作成しようとすると、NullPointerExceptionが発生します。

8
1615903

マップでヌルを許可するとエラーになります。見ることができます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/...を渡すと、私たちも文句を言うほど厳格です。

5
GhostCat

すべてのマップがキーとしてnullを許可するわけではありません

docs of Map に記載されている理由。

一部のマップ実装には、含まれるキーと値に制限があります。たとえば、一部の実装ではヌルのキーと値が禁止されており、一部の実装ではキーのタイプに制限があります。不適格なキーまたは値を挿入しようとすると、未チェックの例外、通常はNullPointerExceptionまたはClassCastExceptionがスローされます。

3
Suresh Atta

ドキュメントにはwhynullは許可されていませんと書かれていません。

nullキーと値を許可しません。 nullキーまたは値でそれらを作成しようとすると、NullPointerExceptionになります。

私の意見では、定数を生成するMap.of()およびMap.ofEntries()静的ファクトリーメソッドは、ほとんどがコンパイルタイプの開発者によって形成されます。次に、nullをキーまたは値として保持する理由は何ですか?

一方、Map#putは通常、実行時にnullキー/値が発生する可能性のあるマップを埋めるために使用されます。

2
Andrew Tobilko