Java | Java 標準ライブラリ:Optional.ifPresent

Java Java
スポンサーリンク

ifPresent は「値があるときだけ処理するためのスイッチ」

Optional.ifPresent は、

「Optional の中に値が“入っているときだけ” この処理を実行してね」

と言うためのメソッドです。

雰囲気としては、次の if 文の短縮形です。

Optional<String> opt = ...;

if (opt.isPresent()) {
    String value = opt.get();
    // value を使った処理
}
Java

これを ifPresent を使うと、こう書けます。

opt.ifPresent(value -> {
    // value を使った処理
});
Java

isPresent()get() を自分で書かずに済み、
「値があるときだけ○○する」というパターンを一発で表現できるのがポイントです。


一番シンプルな例でイメージをつかむ

ユーザー名が存在するときだけ表示したい

例えば、「ユーザー名が存在する場合だけ表示したい」状況を考えます。

まずは Optional なし版(null チェック版)です。

String name = findUserNameOrNull(userId); // 見つからないとき null

if (name != null) {
    System.out.println("ようこそ " + name + " さん");
}
Java

これを Optional を使う形で書くと:

Optional<String> nameOpt = findUserName(userId); // Optional<String> を返す

nameOpt.ifPresent(name ->
    System.out.println("ようこそ " + name + " さん")
);
Java

やっていることは同じですが、

「null かもしれない値」
ではなく
「あるかないか、Optional が知っている値」

として扱えるようになります。

ifPresent の中は、「値があるときにだけ実行される領域」として、
ラムダ(name -> ...)で表現されているイメージです。


ifPresent のシグネチャと「ラムダ」の意味

メソッドの形をちゃんと見る

Optional.ifPresent の宣言はこうなっています。

void ifPresent(Consumer<? super T> action)
Java

少しかみ砕くと、

「T 型の値を1つ受け取って、何も返さないメソッド(Consumer)を受け取る」

という意味です。

Java 8 以降では、Consumer はラムダで簡単に書けます。

opt.ifPresent(value -> {
    // value を使った処理(戻り値は書かない)
});
Java

ここで value は「Optional の中身」が渡されます。
ifPresent の内部では、

中身がある → 渡されたラムダ(Consumer)を実行
中身がない → 何もしない

というシンプルな動きをします。


ifPresent を使わないとどうなるか(null チェックとの対比)

isPresent / get の組み合わせは避けたい

よくないパターンとして、Optional をこう使ってしまうケースがあります。

Optional<User> userOpt = findUser(id);

if (userOpt.isPresent()) {
    User user = userOpt.get();
    System.out.println(user.getName());
}
Java

これ、見た目は素直ですが、

「Optional なのに、結局 isPresent と get をセットで使っているだけ」

になっています。
せっかく Optional を使っているのに、

if (user != null) { ... user ... }

とほぼ変わらないスタイルです。

ifPresent は、まさにこの「isPresent → get → 使う」という
よくあるパターンを置き換えるために存在します。

findUser(id).ifPresent(user ->
    System.out.println(user.getName())
);
Java

こう書くことで、

「値があるときの処理」がラムダの中に閉じ込められ、
get() を外に漏らさずに済みます。


「副作用がある時にだけやりたい処理」に特に向いている

ログ出力や保存処理など

ifPresent が特にしっくりくるのは、「副作用のある処理」をやりたいときです。

例えば、「ユーザーが見つかったときだけログに出したい」場合。

Optional<User> userOpt = findUser(id);

userOpt.ifPresent(user ->
    logger.info("ログイン成功: " + user.getName())
);
Java

または、「設定値があれば DB に保存する」といったケース。

Optional<String> optConfig = loadConfig("timeout");

optConfig.ifPresent(value ->
    repository.saveTimeout(value)
);
Java

「値があるなら、これを実行する」
「値がなければ、何もしない」

というパターンを、そのままコードに落とし込めます。


ifPresent だけでは「無いときの処理」が書けない

「あるときは A、ないときは B」を書きたい場合

ここが初心者が最初につまずきやすいポイントです。

ifPresent は「あるときだけ」の処理しか書けません。
「無いときに何かする」ロジックを足したくなると、
ついこう書いてしまいがちです。

Optional<User> userOpt = findUser(id);

if (userOpt.isPresent()) {
    // 見つかったとき
    User user = userOpt.get();
    System.out.println(user.getName());
} else {
    // 見つからなかったとき
    System.out.println("ユーザーが見つかりません");
}
Java

これはこれで正しいのですが、
Optional をせっかく使っているのに、
「従来の if-else と get の組み合わせ」に戻ってしまっています。

「あるときは A、ないときは B」という分岐を Optional で書くなら、
orElse / orElseGet / orElseThrow と組み合わせるのが自然です。

例えば、「見つからなかったらエラーにしたい」なら:

User user = findUser(id)
        .orElseThrow(() -> new IllegalArgumentException("ユーザーが存在しません"));
Java

「見つからなかったらデフォルトユーザーにしたい」なら:

User user = findUser(id)
        .orElseGet(() -> createGuestUser());
Java

ifPresent は、「ないときの処理」を書く場ではなく、
「あるときだけ実行したい副作用」を書く場と捉えておくと整理しやすくなります。


よくある「やりすぎな使い方」とその注意点

ifPresent の中でさらに条件分岐しすぎない

例えば、こういうコードは少し読みにくくなります。

findUser(id).ifPresent(user -> {
    if (user.isActive()) {
        sendMail(user);
    } else {
        logger.warn("無効ユーザーです");
    }
});
Java

処理自体は間違っていませんが、
ifPresent のラムダがどんどん大きくなると、
「値があるときにやりたい処理」が見えづらくなります。

そういうときは、ラムダの中身をメソッドに切り出すのも手です。

findUser(id).ifPresent(this::handleUser);

private void handleUser(User user) {
    if (user.isActive()) {
        sendMail(user);
    } else {
        logger.warn("無効ユーザーです");
    }
}
Java

ifPresent(this::handleUser) と書けると、
「ユーザーがいるときに handleUser を呼ぶ」という意図がクリアになります。


まとめ:ifPresent をどういう感覚で使うか

Optional.ifPresent を、一言でまとめるとこうです。

「Optional に値があるときだけ、この処理をする」を
isPresent + get なしでスッキリ書くためのメソッド。

もう少し分解すると、

Optional の中身が null かどうかを意識せずに、「あるときだけ副作用を起こす」コードが書ける
isPresent()get() のセットを避けることで、「Optional を本当に Optional らしく使える」
「ないときの処理」は ifPresent ではなく orElse系orElseThrow に任せる、と役割分担すると整理しやすい

という立ち位置になります。

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