【プログラミングしてみよう22】JavaのOptionalでnullを安全に扱う

Java

前回はenumを使って決まった種類の値を安全に管理する方法を学びました。

今回は「Optional」について解説します。 Javaプログラムでよく起きるエラーのひとつに「NullPointerException」があります。Optionalを使うことで、nullになる可能性のある値を安全に扱えるようになります。

NullPointerExceptionとは

NullPointerException(NPE)は、null の変数に対してメソッドを呼び出したり、フィールドにアクセスしたりしたときに発生するエラーです。Javaプログラムで最もよく見かけるエラーのひとつで、「nullポインタ例外」とも呼ばれます。

String name = null;
System.out.println(name.length()); // NullPointerException 発生!

これまでの対処法は、nullチェックを if 文で行うことでした。

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

しかし、nullチェックが必要な箇所が増えると、コードが読みにくくなりがちです。Java 8から導入された Optional を使うと、「この値はnullかもしれない」という意図をコードで明示しながら、安全に操作できるようになります。

Optionalの基本

Optional<T> は、値が存在するかもしれないし、存在しないかもしれないことを表すクラスです。

// 値ありのOptionalを作る
Optional<String> opt1 = Optional.of("ぱんまる");

// 値なし(null)のOptionalを作る
Optional<String> opt2 = Optional.empty();

// nullかもしれない値からOptionalを作る
Optional<String> opt3 = Optional.ofNullable(someValue);

よく使うメソッドは以下の通りです。

isPresent()   // 値が存在すればtrue
isEmpty()     // 値が存在しなければtrue (Java 11以降)
get()         // 値を取り出す(値がない場合は例外)
orElse()      // 値がない場合のデフォルト値を指定
orElseGet()   // 値がない場合の処理をラムダ式で指定
ifPresent()   // 値がある場合だけ処理を実行

サンプルコード(Optionalの基本操作)

ファイル作成

「Java11」フォルダに OptionalTest.java という名前でファイルを作成します

コード入力

以下のコードを入力します。

import java.util.Optional;

public class OptionalTest {
    public static void main(String[] args) {
        Optional<String> optName = Optional.of("ぱんまる");
        Optional<String> optEmpty = Optional.empty();

        // isPresent で値の有無を確認
        System.out.println("optName isPresent: " + optName.isPresent());
        System.out.println("optEmpty isPresent: " + optEmpty.isPresent());

        // get で値を取り出す
        System.out.println("optName get: " + optName.get());

        // orElse でデフォルト値を指定
        System.out.println("optEmpty orElse: " + optEmpty.orElse("名無し"));

        // orElseGet でラムダ式を指定
        System.out.println("optEmpty orElseGet: " + optEmpty.orElseGet(() -> "デフォルト名"));

        // ifPresent で値がある場合だけ処理
        optName.ifPresent(name -> System.out.println("こんにちは、" + name + "さん!"));
        optEmpty.ifPresent(name -> System.out.println("これは表示されません"));
    }
}

コンパイル

javac OptionalTest.java

実行

java OptionalTest

実行結果は次のようになります。

optName isPresent: true
optEmpty isPresent: false
optName get: ぱんまる
optEmpty orElse: 名無し
optEmpty orElseGet: デフォルト名
こんにちは、ぱんまるさん!

サンプルコード(Optionalとメソッドの組み合わせ)

ファイル作成

「Java11」フォルダに UserFinder.java という名前でファイルを作成します

コード入力

以下のコードを入力します。

import java.util.Optional;

public class UserFinder {
    public static Optional<String> findUserById(int id) {
        if (id == 1) {
            return Optional.of("ぱんまる");
        } else {
            return Optional.empty();
        }
    }

    public static void main(String[] args) {
        int[] ids = {1, 2, 3};

        for (int id : ids) {
            Optional<String> user = findUserById(id);
            String result = user.orElse("ユーザーが見つかりません");
            System.out.println("ID " + id + " : " + result);
        }
    }
}

コンパイル

javac UserFinder.java

実行

java UserFinder

実行結果は次のようになります。

ID 1 : ぱんまる
ID 2 : ユーザーが見つかりません
ID 3 : ユーザーが見つかりません

コードの解説

Optional.of("ぱんまる") は値ありのOptionalを作ります。Optional.empty() は値なし(nullに相当)のOptionalを作ります。値がnullかもしれない場合は Optional.ofNullable(value) を使うと、nullなら自動的に Optional.empty() になります。

orElse("名無し") は、値がない場合に括弧内の値を返します。値がある場合はそちらが使われます。orElseGet(() -> "デフォルト名") は、orElse と似ていますが、ラムダ式を使って値が必要になったときだけ処理を実行するため、デフォルト値の生成コストが高い場合に向いています。

ifPresent(name -> ...) は値がある場合だけラムダ式の処理を実行します。if (opt.isPresent()) { ... } と書く代わりにこちらを使うと、より簡潔に書けます。

findUserById メソッドの戻り値を Optional<String> にすることで、「この戻り値はnullになることがある」という意図がメソッドのシグネチャから明確に伝わります。呼び出す側では orElse などで必ずnullの場合の処理を書くことが促されるため、nullチェックの書き忘れを防ぎやすくなります。

なお、get() は値がない状態で呼ぶと NoSuchElementException が発生します。get() を使う前には必ず isPresent() で確認するか、orElseifPresent を使う書き方が推奨されます。

まとめ

Optionalを使うことで、nullになる可能性のある値を明示的に表現し、NullPointerExceptionを防ぎやすくなります。orElse でデフォルト値を指定したり、ifPresent で値がある場合だけ処理したりと、nullチェックのif文を使わずに安全なコードが書けるようになります。メソッドの戻り値にOptionalを使うことで、「この値はnullかもしれない」という意図をコードで伝えることができ、呼び出す側での対処が促されます。nullとの戦いはJavaプログラミングの永遠のテーマですが、Optionalをうまく活用することでより安全で読みやすいコードに近づけます。

2026/07/01(水) ぱんまる

コメント

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