0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaのOptionalで学ぶnull安全 — nullチェックだらけのコードを綺麗にする方法

0
Posted at

JavaのOptionalで学ぶnull安全 — nullチェックだらけのコードを綺麗にする方法

はじめに

Javaを書いていると、避けて通れないのがNullPointerException(通称NPE)です。

String name = user.getName();
System.out.println(name.length()); // userがnullだったら? → NPE!

これを防ごうとすると、こうなりがちです。

if (user != null) {
    String name = user.getName();
    if (name != null) {
        System.out.println(name.length());
    }
}

nullチェックのネスト地獄。読みにくいし、書くのも面倒。

Java 8で導入されたOptionalを使えば、このnullチェックをもっとスマートに書けます。


Optionalとは何か

Optionalは、「値があるかもしれないし、ないかもしれない」を表現するクラスです。

Optional<String> name = Optional.of("田中");       // 値あり
Optional<String> empty = Optional.empty();          // 値なし
Optional<String> nullable = Optional.ofNullable(null); // nullならempty

「nullかもしれない値」をOptionalで包むことで、nullを直接触らずに安全に扱えるのがポイントです。


基本的な使い方

1. isPresent() / isEmpty() — 値があるか確認

Optional<String> name = Optional.ofNullable(getName());

if (name.isPresent()) {
    System.out.println(name.get());
}

// Java 11以降
if (name.isEmpty()) {
    System.out.println("名前がありません");
}

ただし、これだとnullチェックとあまり変わりません。Optionalの真価は次からです。

2. ifPresent() — 値があるときだけ処理する

Optional<String> name = Optional.ofNullable(getName());

name.ifPresent(n -> System.out.println("名前: " + n));

nullチェックのif文が消えて、1行で安全に処理できます。

3. orElse() / orElseGet() — デフォルト値を返す

String name = Optional.ofNullable(getName())
    .orElse("名無し");

// 重い処理でデフォルト値を生成する場合はorElseGet
String name = Optional.ofNullable(getName())
    .orElseGet(() -> generateDefaultName());

4. map() — 値を変換する

Optional<String> upperName = Optional.ofNullable(getName())
    .map(String::toUpperCase);

値がnullなら変換はスキップされ、Optional.empty()が返ります。チェーンで安全に変換できます。

5. flatMap() — Optionalを返すメソッドをつなげる

Optional<String> city = Optional.ofNullable(user)
    .flatMap(User::getAddress)    // AddressがOptionalで返る
    .flatMap(Address::getCity);   // CityもOptionalで返る

ネストしたOptionalをフラットにつなげてくれます。


実務でよくあるパターン

Before: nullチェックだらけ

public String getUserCity(User user) {
    if (user != null) {
        Address address = user.getAddress();
        if (address != null) {
            String city = address.getCity();
            if (city != null) {
                return city;
            }
        }
    }
    return "不明";
}

After: Optionalでスッキリ

public String getUserCity(User user) {
    return Optional.ofNullable(user)
        .map(User::getAddress)
        .map(Address::getCity)
        .orElse("不明");
}

ネストが消えて、処理の流れが一目でわかるようになりました。


Optionalを使う時の注意点

やってはいけないこと

// NG: get()を直接呼ぶ(NoSuchElementExceptionの危険)
Optional<String> name = Optional.empty();
name.get(); // 例外が飛ぶ!

// NG: フィールドにOptionalを使う
public class User {
    private Optional<String> name; // これはNG
}

// NG: メソッドの引数にOptionalを使う
public void greet(Optional<String> name) { // これもNG
}

Optionalの正しい使いどころ

使い方 OK / NG
メソッドの戻り値 OK(本来の使い方)
フィールド NG(Serializableではない)
メソッドの引数 NG(呼び出し側が複雑になる)
コレクションの要素 NG(空のコレクションで代替)

Optionalは「戻り値がnullかもしれない」ことを明示するための道具です。


Stream APIとの組み合わせ

Java 9以降、OptionalとStream APIを組み合わせるとさらに便利です。

// Optional → Stream変換(Java 9+)
List<String> names = users.stream()
    .map(User::getName)           // Optional<String>が返る場合
    .flatMap(Optional::stream)    // 値があるものだけ取り出す
    .collect(Collectors.toList());

まとめ

メソッド 用途
ofNullable() null許容のOptionalを作成
ifPresent() 値があるときだけ処理
orElse() デフォルト値を指定
map() 値を変換
flatMap() Optional同士をつなげる

Optionalを使うと:

  • nullチェックのネストが消える
  • 「この値はnullかも」が型で伝わる
  • NPEのリスクが減る

おわりに

Optionalは最初「nullチェックと何が違うの?」と思いがちですが、使い慣れるとコードの安全性と可読性が格段に上がります。

特にmap()とorElse()の組み合わせは実務で頻出するので、ぜひ手を動かして試してみてください。

nullとの戦いが少し楽になるはずです。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?