ifPresent は「値があるときだけ処理するためのスイッチ」
Optional.ifPresent は、
「Optional の中に値が“入っているときだけ” この処理を実行してね」
と言うためのメソッドです。
雰囲気としては、次の if 文の短縮形です。
Optional<String> opt = ...;
if (opt.isPresent()) {
String value = opt.get();
// value を使った処理
}
Javaこれを ifPresent を使うと、こう書けます。
opt.ifPresent(value -> {
// value を使った処理
});
JavaisPresent() と 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());
JavaifPresent は、「ないときの処理」を書く場ではなく、
「あるときだけ実行したい副作用」を書く場と捉えておくと整理しやすくなります。
よくある「やりすぎな使い方」とその注意点
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("無効ユーザーです");
}
}
JavaifPresent(this::handleUser) と書けると、
「ユーザーがいるときに handleUser を呼ぶ」という意図がクリアになります。
まとめ:ifPresent をどういう感覚で使うか
Optional.ifPresent を、一言でまとめるとこうです。
「Optional に値があるときだけ、この処理をする」をisPresent + get なしでスッキリ書くためのメソッド。
もう少し分解すると、
Optional の中身が null かどうかを意識せずに、「あるときだけ副作用を起こす」コードが書けるisPresent() → get() のセットを避けることで、「Optional を本当に Optional らしく使える」
「ないときの処理」は ifPresent ではなく orElse系 や orElseThrow に任せる、と役割分担すると整理しやすい
という立ち位置になります。
