Java Tips | 基本ユーティリティ:Objects.requireNonNullElseGet()

Web APP Java
スポンサーリンク
スポンサーリンク

Objects.requireNonNullElseGet()とは何か

Javaで業務システムを開発していると、「値がnullだった場合は代替値を使いたい」という場面によく遭遇します。

そのようなケースでは、前回紹介した Objects.requireNonNullElse() が便利です。

しかし実務では、デフォルト値の生成にコストがかかることがあります。

例えば、

  • データベースアクセス
  • API呼び出し
  • ファイル読み込み
  • 大量データの生成
  • 複雑なオブジェクト生成

などです。

そのような場合に利用するのが、 Objects.requireNonNullElseGet() です。

Objects.requireNonNullElseGet(
        値,
        Supplier
);
Java

このメソッドは、 「本当にnullだった場合だけデフォルト値を生成する」 という特徴があります。

この仕組みを「遅延評価(Lazy Evaluation)」または「遅延生成」と呼びます。

業務システムでは性能改善や無駄な処理削減のためによく利用されます。

まずはrequireNonNullElse()の問題点を知ろう

初心者の方は、

Objects.requireNonNullElse()
Java

だけで十分ではないかと思うかもしれません。

まずは次のコードを見てください。

// ユーザー情報
User user = findUser();

// デフォルト値を指定
User result =
        Objects.requireNonNullElse(
                user,
                createGuestUser()
        );
Java

一見問題なさそうに見えます。

しかし実は、 createGuestUser() は必ず実行されます。

たとえuserがnullでなくてもです。

つまり不要なオブジェクト生成が発生している可能性があります。

requireNonNullElseGet()は何が違うのか

requireNonNullElseGet()は、 デフォルト値を直接渡すのではなく、 Supplierという仕組みを利用して後で生成します。

// ユーザー情報取得
User user = findUser();

// nullの場合だけ生成
User result =
        Objects.requireNonNullElseGet(
                user,
                () -> createGuestUser()
        );
Java

この場合、

  • userが存在する → createGuestUser()は実行されない
  • userがnull → createGuestUser()が実行される

という動作になります。

これが「遅延デフォルト」と呼ばれる理由です。

ステップバイステップで理解する

ステップ1:元の値を準備する

// 元のユーザー
String name = null;
Java

現在は値が存在しません。

ステップ2:デフォルト生成処理を用意する

// デフォルト値生成
() -> "ゲスト"
Java

まだ実行はされません。

「必要になったら実行してください」 という予約だけを行っています。

ステップ3:requireNonNullElseGet()を実行する

// nullならデフォルト生成
String result =
        Objects.requireNonNullElseGet(
                name,
                () -> "ゲスト"
        );
Java

ステップ4:結果を確認する

// 結果表示
System.out.println(result);
Java

実行結果

ゲスト

nameがnullだったため、Supplierが実行されました。

nullではない場合はどうなるのか

// 値あり
String name = "Tanaka";

// nullではない
String result =
        Objects.requireNonNullElseGet(
                name,
                () -> {
                    System.out.println("実行されました");
                    return "ゲスト";
                }
        );

System.out.println(result);
Java

実行結果

Tanaka

「実行されました」は表示されません。

つまりSupplier自体が実行されていないことが分かります。

Supplierとは何か

requireNonNullElseGet()を理解するためにはSupplierを知る必要があります。

Supplierは、 「値を後で作って返すための仕組み」 です。

イメージとしては次のようなものです。

// 値を後で作る予約
() -> "ゲスト"
Java

これは、

public String get() {
    return "ゲスト";
}
Java

に近い意味になります。

実務ではLambda式で記述するケースがほとんどです。

業務システムでよくある利用例

デフォルトユーザー生成

// ユーザー取得
User user = userRepository.findById(id);

// 見つからない場合のみ生成
User result =
        Objects.requireNonNullElseGet(
                user,
                () -> new User("ゲスト")
        );
Java

ユーザーが存在する場合は不要なオブジェクト生成を回避できます。

設定値の取得

// 設定取得
String apiKey = config.getApiKey();

// 未設定なら生成
apiKey =
        Objects.requireNonNullElseGet(
                apiKey,
                () -> loadDefaultApiKey()
        );
Java

設定値が存在するならファイル読み込みは行われません。

キャッシュ処理

// キャッシュ検索
Data data = cache.get(key);

// なければ生成
data =
        Objects.requireNonNullElseGet(
                data,
                () -> createData()
        );
Java

キャッシュシステムでは非常によく使われる考え方です。

requireNonNullElse()との違い

requireNonNullElse()

// 常に実行される
Objects.requireNonNullElse(
        user,
        createGuestUser()
);
Java

createGuestUser()は必ず実行されます。

requireNonNullElseGet()

// 必要な時だけ実行
Objects.requireNonNullElseGet(
        user,
        () -> createGuestUser()
);
Java

userがnullの場合だけ実行されます。

これが最大の違いです。

特に重要:パフォーマンス改善効果

実務でrequireNonNullElseGet()が採用される最大の理由はここです。

例えば次の処理を考えてみます。

// DBアクセスが発生する処理
User createGuestUser() {

    System.out.println("DBアクセス");

    return userRepository.findGuestUser();
}
Java

requireNonNullElse()を使うと毎回DBアクセスが発生する可能性があります。

一方でrequireNonNullElseGet()なら、 本当に必要な時だけ実行されます。

高負荷システムでは大きな性能差になる場合があります。

初心者が間違えやすいポイント

デフォルト値ではなくSupplierを渡す

間違った書き方です。

// NG
Objects.requireNonNullElseGet(
        user,
        createGuestUser()
);
Java

正しくはこちらです。

// OK
Objects.requireNonNullElseGet(
        user,
        () -> createGuestUser()
);
Java

Supplierを渡す必要があります。

デフォルト生成結果はnull禁止

実はSupplierの戻り値もnullを許可しません。

// NG
Objects.requireNonNullElseGet(
        null,
        () -> null
);
Java

実行結果

NullPointerException

代替値は必ず存在する必要があります。

実務で使えるテンプレート集

文字列テンプレート

// nullなら生成
String value =
        Objects.requireNonNullElseGet(
                inputValue,
                () -> "DEFAULT"
        );
Java

オブジェクトテンプレート

// ユーザー生成
User user =
        Objects.requireNonNullElseGet(
                inputUser,
                () -> new User("Guest")
        );
Java

設定値テンプレート

// 設定値読込
String endpoint =
        Objects.requireNonNullElseGet(
                configValue,
                () -> loadDefaultEndpoint()
        );
Java

キャッシュテンプレート

// キャッシュ取得
Data data =
        Objects.requireNonNullElseGet(
                cache.get(key),
                () -> loadData(key)
        );
Java

情報セキュリティの観点から見る重要性

業務システムでは外部システムやデータベースから取得した値が欠損することがあります。

その際、

  • 無条件で処理を停止するべきか
  • 代替値で継続できるか

を適切に判断する必要があります。

requireNonNullElseGet()は、 安全な代替値を必要な時だけ生成する仕組みです。

そのため、

  • システム可用性向上
  • 不要なリソース消費削減
  • 障害発生率低下
  • 性能改善

に貢献します。

ただし認証情報や権限情報などの重要データは、安易にデフォルト値へ置き換えず例外として扱うべき場合もあります。

まとめ

Objects.requireNonNullElseGet()は、値がnullだった場合のみデフォルト値を生成するためのユーティリティメソッドです。

  • nullならSupplierを実行する
  • nullでなければ元の値を返す
  • 遅延評価によって無駄な処理を防げる
  • requireNonNullElse()より高性能な場合がある
  • デフォルト値生成コストが高い場合に特に有効
  • キャッシュ処理や設定値取得で頻繁に利用される
  • 実務では性能最適化のためによく採用される

特に業務システムでは、「値が存在する場合は余計な処理をしたくない」という場面が数多くあります。そのようなケースでObjects.requireNonNullElseGet()を利用すると、コードの可読性を維持しながらパフォーマンスと保守性を向上させることができます。

タイトルとURLをコピーしました