JavaのBooleanをif条件で使うとNullPointerExceptionになる理由を解説する記事のアイキャッチ。

Java

JavaのBooleanでNullPointerExceptionになる理由|自動アンボクシングの注意

AIによる要約

Booleanはtrue・falseに加えてnullを持てます。if(flag)やboolean変数への代入ではBooleanからbooleanへの自動アンボクシングが行われ、flagがnullだとNullPointerExceptionになります。trueだけを判定するならBoolean.TRUE.equals(flag)、必ず二値なら最初からbooleanを使います。nullを『未設定』『未回答』『対象外』として使うなら、三値の意味を明示し、既定値で潰してよいか確認します。

新人SE
新人SE
if (enabled)の行でNullPointerExceptionになりました。enabledはBooleanです。
ポンコツSE
ポンコツSE
Booleanのnullをbooleanへ変換しようとして失敗しています。自動アンボクシングが原因です。

booleanはtrueかfalseだけですが、ラッパークラスのBooleanはnullも持てます。DBのNULL、JSONの項目省略、Map#get、未初期化のDTOなどからnullが入り、if条件へ渡した瞬間に例外になることがあります。

対策としてBoolean.TRUE.equalsを覚えるだけでなく、なぜBooleanを使っているのか確認してください。nullに業務上の意味がないならbooleanへ寄せ、意味があるなら三値を仕様として扱います。

この記事のポイント

  • Booleanはnullを持てるがbooleanは持てない
  • if(flag)では自動アンボクシングが起きる
  • nullをtrue以外として扱うならBoolean.TRUE.equalsを使える
  • 二値で十分ならbooleanを選ぶ
  • 三値のnullをfalseへ潰してよいか業務仕様を確認する

if条件で自動アンボクシングが起きる

ifはboolean値を必要とします。Booleanを渡すと、Javaが内部でflag.booleanValue()相当の処理を行います。flagがnullならメソッドを呼べずNullPointerExceptionです。

Boolean enabled = null;

if (enabled) { // NullPointerException
    execute();
}

スタックトレースはif行を指すため、条件式にメソッドがなくても例外になります。変数の宣言型と代入元を追います。

Boolean.TRUE.equalsでtrueだけを判定する

nullをfalse側として扱ってよい場合、nullにならない定数側からequalsを呼びます。

if (Boolean.TRUE.equals(enabled)) {
    execute();
}

enabledがtrueのときだけ処理し、falseとnullでは実行しません。ただし、nullが『未回答』を意味し、falseが『明確に拒否』を意味するなら、同じ分岐にまとめてはいけません。

falseを判定するときの注意

Boolean.FALSE.equals(flag)は、flagがfalseのときだけtrueで、nullはfalseになります。!Boolean.TRUE.equals(flag)はfalseとnullの両方でtrueです。似ていますが意味が違います。

Boolean flag = null;

System.out.println(Boolean.FALSE.equals(flag)); // false
System.out.println(!Boolean.TRUE.equals(flag));  // true

否定条件ほどレビューで読み違えます。未設定を含めるのか、明示的なfalseだけなのかをメソッド名や分岐で表します。

二値ならbooleanを選ぶ

必須チェックボックス、内部処理の成功可否、設定済みの機能フラグなど、必ずtrueかfalseならプリミティブbooleanを使うとnull状態を排除できます。

class FeatureSetting {
    private boolean enabled;
}

ただしJSONで項目省略とfalseを区別したい更新APIではBooleanが必要なことがあります。Formや外部DTOではBoolean、Serviceへ渡すコマンドではbooleanというように、境界で意味を確定させます。

DBのNULLとデフォルト値

既存テーブルへフラグ列を追加した際、過去データがNULLになることがあります。Java側だけfalseへ変換すると、DB上の未移行データを隠す場合があります。

Boolean active = entity.getActive();
if (active == null) {
    throw new IllegalStateException("activeが未移行です");
}

NOT NULL制約とデフォルト値を追加できるなら、DBとEntityの契約をそろえます。段階移行中はnullを検知し、移行完了後にBooleanからbooleanへ変える計画も検討します。

JSONの項目省略とfalseを区別する

PATCHのような部分更新では、項目がないことを『変更しない』、falseを『無効化する』と扱うことがあります。この場合Booleanのnullに意味があります。

void apply(UpdateUserRequest request, User user) {
    if (request.active() != null) {
        user.setActive(request.active());
    }
}

単純な新規登録APIで必須なら、Validationでnullを拒否し、内部へ入る前にbooleanへ確定します。APIの種類ごとに契約を分けます。

Optionalで解決するとは限らない

Optionalなら未設定を表せますが、true・false・emptyの3状態がある点は同じです。さらにシリアライズやJPAとの相性、プロジェクト規約もあります。

三値が本当に必要なら、UNANSWEREDACCEPTEDREJECTEDのenumにすると意味が明確な場合があります。Booleanで表せるかではなく、業務状態を読み手が理解できるかで選びます。

JUnitで三状態をテストする

Booleanを受け取る処理はtrueとfalseだけでなくnullもテストします。nullをfalse扱いするのか、入力エラーにするのか、未変更にするのかを固定します。

@ParameterizedTest
@NullSource
@ValueSource(booleans = {false})
void true以外では処理しない(Boolean enabled) {
    assertFalse(service.shouldExecute(enabled));
}

@Test
void trueなら処理する() {
    assertTrue(service.shouldExecute(Boolean.TRUE));
}

現場レビューでよくある指摘

BooleanのレビューではNPE回避だけでなく、nullが不要な状態か、業務上の第三状態かを確認します。

// レビューコメント例
enabledはBooleanなので、null時にif条件のアンボクシングでNPEになります。
二値ならbooleanへ変更してください。

// レビューコメント例
Boolean.TRUE.equalsならnullをfalse側へ寄せられますが、
未回答と拒否を同じにしてよいか仕様を確認してください。

// レビューコメント例
更新APIでは項目省略を「変更なし」と扱うため、Booleanのnullに意味があります。
Controller境界で三状態を明示してください。

NPEを直すためにnullを一律falseへ変換せず、代入元と業務状態を確認します。二値へ狭められる場所ではbooleanを使い、三値が必要な場所だけBooleanを残します。

提出前のセルフチェック

レビュー前に確認すること

  • Booleanがnullになる入口を確認したか
  • if条件でアンボクシングしていないか
  • Boolean.TRUE.equalsが仕様に合うか
  • falseとnullを区別する必要があるか
  • 二値ならbooleanへ変更できないか
  • DB列のNULLとNOT NULL制約を確認したか
  • JSON項目省略とfalseを区別したか
  • true・false・nullをテストしたか

Javaの型とnullを整理する参考書

プリミティブ型、ラッパークラス、オートボクシングを体系的に確認すると、条件式で突然起きるNullPointerExceptionの原因を追いやすくなります。

書籍「スッキリわかるJava入門 第5版」の表紙
商品画像:Amazon.co.jp
PR Java初学者向け

スッキリわかるJava入門 第5版

中山 清喬 (著), 国本 大悟 (著), 株式会社フレアリンク (監修)

Java文法とオブジェクト指向を、最初から整理する一冊。

豊富な図とサンプルで、変数、条件分岐、クラス、例外処理まで順番に学べます。Javaの最初の教科書を探している人向けです。

  • Javaを基礎から体系的に学びたい
  • Java 25 LTS対応の入門書を選びたい

当サイトはAmazonアソシエイト・プログラムの参加者です。価格・在庫・配送条件はAmazonでご確認ください。

この記事とあわせて読みたい

まとめ

Booleanをif条件やboolean変数へ使うと自動アンボクシングが起き、値がnullならNullPointerExceptionになります。trueだけを判定するならBoolean.TRUE.equalsを使えます。

ただし最も重要なのは、nullが不要か第三状態かを決めることです。二値ならboolean、未回答や未変更を表すならBooleanやenumを使い、三状態をテストしてください。

-Java
-, , ,