AIによる要約
HashMapのgetがnullを返すのは、キーが登録されていない場合と、キーに対してnull値が登録されている場合の2通りです。getだけでは区別できないため、区別が必要ならcontainsKeyを使います。getOrDefaultもnull値が登録されている場合はnullを返すため、常に既定値になるわけではありません。可能ならMapへnullを格納せず、未登録・取得失敗・値なしの意味を設計上分けます。


Mapはマスタ値、表示名、集計結果、キャッシュなど幅広く使われます。`get(key) == null`を「キーなし」と決めつけると、登録済みだが値未設定という状態を見落とします。
逆に、毎回containsKeyしてからgetする必要もありません。null値を格納しない設計なら、getのnullを未登録として扱えます。重要なのはそのMapでnullが何を意味するかを決めることです。
この記事のポイント
- HashMap.getのnullには2つの意味がある
- containsKeyでキーの登録有無を区別できる
- getOrDefaultは登録済みnullを既定値へ置き換えない
- computeIfAbsentはnullを「値なし」として扱う
- 可能ならMapへnullを入れない設計にする
XのJavaクイズで2種類のnullを確認する

Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", null);
System.out.println(scores.get("Alice"));
System.out.println(scores.get("Bob"));どちらもnullです。getの結果だけでは、AliceとBobの違いを判定できません。

containsKeyでキーの有無を判定する
System.out.println(scores.containsKey("Alice")); // true
System.out.println(scores.containsKey("Bob")); // falseHashMapはキーと値の組を保持します。Aliceはキーが存在し、対応する値がnullです。Bobはキーが存在しません。`containsKey`は値ではなくキーの登録有無を確認します。
Integer score = scores.get(name);
if (score != null) {
return "点数: " + score;
}
if (scores.containsKey(name)) {
return "採点前";
}
return "受験者なし";この例では、数値あり、キーありnull、キーなしに別の意味を持たせています。業務仕様で3状態が本当に必要な場合だけ、この区別を使います。
getOrDefaultも登録済みnullには効かない
Map<String, String> labels = new HashMap<>();
labels.put("A", null);
System.out.println(
labels.getOrDefault("A", "未設定")); // null
System.out.println(
labels.getOrDefault("B", "未設定")); // 未設定`getOrDefault`が既定値を返すのは、キーが存在しない場合です。キーAは存在するため、登録値nullがそのまま返ります。「nullなら常に既定値」というAPIではありません。
nullも既定値へ置き換えたいなら、要件を明示して処理します。
String label = labels.get(code);
if (label == null) {
label = "未設定";
}ただし、この書き方ではキーなしと登録済みnullを同じ扱いにしています。それで正しいか確認します。
computeIfAbsentでキャッシュする時の注意
User user = cache.computeIfAbsent(
userId,
id -> userRepository.findById(id)
.orElse(null));`computeIfAbsent`はキーに値がない、または現在の値がnullの場合に計算処理を呼びます。ただし計算結果がnullなら、そのnullを新しい値として登録しません。次回もRepository検索が走ります。
「見つからなかったこと」もキャッシュしたいなら、Optionalや専用の結果型を値にする方法があります。
Map<Long, Optional<User>> cache = new HashMap<>();
Optional<User> user = cache.computeIfAbsent(
userId,
userRepository::findById);ただしキャッシュの有効期限、更新、メモリ上限、同時実行まで考える必要があります。本番用途ではCaffeineやSpring Cacheなど案件標準の仕組みを優先し、HashMapで独自キャッシュを作らない方が安全です。
Mapへnullを入れない設計を優先する
3状態が不要なら、nullを格納しない方が呼び出し側は単純になります。
Map<String, Integer> scores = new HashMap<>();
// 採点済みだけ登録する
if (score != null) {
scores.put(studentName, score);
}未採点を表したいなら、nullではなく状態を持つ型にできます。
record ScoreResult(
ScoreStatus status,
Integer score) {
}
enum ScoreStatus {
NOT_GRADED,
GRADED
}少しコードは増えますが、nullの意味をコメントで補わず型で表せます。業務上重要な状態ほど、nullへ複数の意味を詰め込まないようにします。
HashMap以外ではnullの仕様が違う
Mapインターフェースを実装するすべてのクラスがnullを許すわけではありません。たとえば`ConcurrentHashMap`はnullキーとnull値を許可しません。`Map.of`もnullを許可しません。
Map<String, String> map = new ConcurrentHashMap<>();
map.put("A", null); // NullPointerException
Map<String, String> fixed = Map.of(
"A", null); // NullPointerException変数型がMapでも、具体的な生成方法で挙動が変わります。後からHashMapをConcurrentHashMapへ変更する予定があるなら、最初からnullを入れない契約にしておくと移行しやすくなります。
テストで3状態を固定する
@Test
void 登録済みnullとキー未登録を区別する() {
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", null);
assertNull(scores.get("Alice"));
assertTrue(scores.containsKey("Alice"));
assertNull(scores.get("Bob"));
assertFalse(scores.containsKey("Bob"));
}
@Test
void getOrDefaultは登録済みnullを返す() {
Map<String, String> labels = new HashMap<>();
labels.put("A", null);
assertNull(labels.getOrDefault("A", "未設定"));
assertEquals(
"未設定",
labels.getOrDefault("B", "未設定"));
}キーありの値、キーありnull、キーなしを分けてテストします。nullを禁止する設計なら、putする境界で`Objects.requireNonNull`を使うテストも有効です。
現場レビューでよくある指摘
// レビューコメント例
getがnullでも、キー未登録と登録済みnullの両方が考えられます。
このMapで必要な状態を確認し、必要ならcontainsKeyで分けてください。
// レビューコメント例
getOrDefaultはキーAにnullが登録されている場合、既定値を返しません。
nullも置換する要件なら明示的に処理してください。
// レビューコメント例
nullへ「未検索」と「検索済み0件」の2つの意味を持たせています。
結果型かOptionalで状態を分けたいです。提出前のセルフチェック
- Mapのnullが何を意味するか決めたか
- キーなしと登録済みnullを区別する必要があるか
- 必要ならcontainsKeyを使ったか
- getOrDefaultの登録済みnull挙動を理解したか
- computeIfAbsentの計算結果がnullにならないか
- Mapへnullを入れない設計にできないか
- 具体実装がnullを許可するか確認したか
- 3状態をテストしたか
Mapとnullを基礎から整理する参考書
Mapの主要APIと実装クラスの違いを体系的に押さえると、null判定やキャッシュ処理の判断が安定します。
スッキリわかるJava入門 第5版
Java文法とオブジェクト指向を、最初から整理する一冊。
豊富な図とサンプルで、変数、条件分岐、クラス、例外処理まで順番に学べます。Javaの最初の教科書を探している人向けです。
- Javaを基礎から体系的に学びたい
- Java 25 LTS対応の入門書を選びたい
当サイトはAmazonアソシエイト・プログラムの参加者です。価格・在庫・配送条件はAmazonでご確認ください。
この記事とあわせて読みたい
まとめ
HashMap.getがnullを返すのは、キーが存在しない場合と、キーにnull値が登録されている場合の2通りです。区別が必要ならcontainsKeyを使います。
getOrDefaultやcomputeIfAbsentにもnull固有の挙動があります。可能ならMapへnullを格納せず、未登録・検索済み0件・値未設定を型や状態で分け、テストで契約を固定しましょう。
