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


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
三値が本当に必要なら、UNANSWERED、ACCEPTED、REJECTEDの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版
Java文法とオブジェクト指向を、最初から整理する一冊。
豊富な図とサンプルで、変数、条件分岐、クラス、例外処理まで順番に学べます。Javaの最初の教科書を探している人向けです。
- Javaを基礎から体系的に学びたい
- Java 25 LTS対応の入門書を選びたい
当サイトはAmazonアソシエイト・プログラムの参加者です。価格・在庫・配送条件はAmazonでご確認ください。
この記事とあわせて読みたい
まとめ
Booleanをif条件やboolean変数へ使うと自動アンボクシングが起き、値がnullならNullPointerExceptionになります。trueだけを判定するならBoolean.TRUE.equalsを使えます。
ただし最も重要なのは、nullが不要か第三状態かを決めることです。二値ならboolean、未回答や未変更を表すならBooleanやenumを使い、三状態をテストしてください。
