Java : Optional - API使用例

Optional (Java SE 17 & JDK 17) の使用例まとめです。
だいたいのメソッドを網羅済みです。
API仕様のおともにどうぞ。


概要

非null値を含んでも含まなくてもよいコンテナ・オブジェクト。 値が存在する場合、isPresent()はtrueを返します。 値が存在しない場合、オブジェクトはemptyとみなされ、isPresent()はfalseを返します。

クラス構成

Optionalクラスは、対象となる1つの値を、持つこともあれば持たないこともあります。
メソッドの戻り値として、null を返す代わりに Optional を返すことで、nullチェックをよりスマートに記述できます。

もう少し詳しいことは以下の記事にも記載しました。
合わせてご確認いただけたら幸いです。

本記事のコード例には、以下の Sample クラスを使います。

public class Sample<T> {

    private final T value;

    public Sample(T value) {
        this.value = value;
    }

    public Optional<T> getValue() {
        return Optional.ofNullable(value);
    }
}
final var sample = new Sample<>("abcd");

sample.getValue().ifPresent(value -> {
    System.out.println("value : " + value);
});

// 結果
// ↓
//value : abcd
final var sample = new Sample<>(null);

sample.getValue().ifPresentOrElse(value -> {
    System.out.println("value : " + value);
}, () -> {
    System.out.println("value : null!");
});

// 結果
// ↓
//value : null!

メソッド

static <T> Optional<T> empty ()

空のOptionalインスタンスを返します。

final var opt = Optional.empty();

System.out.println(opt); // Optional.empty
System.out.println(opt.isEmpty()); // true
//opt.orElseThrow(); // NoSuchElementException: No value present

boolean equals (Object obj)

他のオブジェクトがこのOptionalに"に等しい"かどうかを示します。

final var opt1 = Optional.of(100);
final var opt2 = Optional.of(100);
final var opt3 = Optional.of(999);

System.out.println(opt1.equals(opt2)); // true
System.out.println(opt1.equals(opt3)); // false
final var opt1 = Optional.of("abcd");
final var opt2 = Optional.of("XYZ");

System.out.println(opt1.equals(opt2)); // false
final var opt1 = Optional.empty();
final var opt2 = Optional.empty();

System.out.println(opt1.equals(opt2)); // true

Optional<T> filter (Predicate<? super T> predicate)

値が存在し、その値が与えられた述語に一致する場合は、値を記述するOptionalを返し、それ以外の場合は空のOptionalを返します。

final var sample = new Sample<>("abcd");

final var ret1 = sample.getValue().filter(s -> {
    System.out.println("filter : " + s);
    return s.equals("abcd");
});
System.out.println("ret : " + ret1);

// 結果
// ↓
//filter : abcd
//ret : Optional[abcd]

final var ret2 = sample.getValue().filter(s -> {
    System.out.println("filter : " + s);
    return s.equals("XYZ");
});
System.out.println("ret : " + ret2);

// 結果
// ↓
//filter : abcd
//ret : Optional.empty
final var sample = new Sample<>(null);

final var ret = sample.getValue().filter(s -> {
    // 空の場合は呼び出されません。
    System.out.println("filter : " + s);
    return s.equals("abcd");
});
System.out.println("ret : " + ret);

// 結果
// ↓
//ret : Optional.empty

<U> Optional<U> flatMap (Function<? super T,? extends Optional<? extends U>> mapper)

値が存在する場合、指定されたOptional-bearingマッピング関数を値に適用した結果を返します。それ以外の場合は空のOptionalを返します。

final var sample = new Sample<>("abcd");

final var ret = sample.getValue().flatMap(s -> {
    System.out.println("flatMap : " + s);
    return Optional.of(s.toUpperCase());
});

System.out.println("ret : " + ret);

// 結果
// ↓
//flatMap : abcd
//ret : Optional[ABCD]
final var sample = new Sample<>(255);

final var ret1 = sample.getValue().flatMap(i -> {
    System.out.println("flatMap : " + i);
    return Optional.of(i * 2);
});

System.out.println("ret : " + ret1);

// 結果
// ↓
//flatMap : 255
//ret : Optional[510]

final var ret2 = sample.getValue().flatMap(i -> {
    System.out.println("flatMap : " + i);
    return Optional.of("0x" + Integer.toHexString(i));
});

System.out.println("ret : " + ret2);

// 結果
// ↓
//flatMap : 255
//ret : Optional[0xff]
final var sample = new Sample<>(null);

final var ret = sample.getValue().flatMap(s -> {
    // 空の場合は呼び出されません。
    System.out.println("flatMap : " + s);
    return Optional.empty();
});

System.out.println("ret : " + ret);

// 結果
// ↓
//ret : Optional.empty

T get ()

値がある場合は値を返し、そうでない場合はNoSuchElementExceptionをスローします。

代わりに、メソッド名が改善された orElseThrow() を使うことをおすすめします。

final var sample = new Sample<>("abcd");

final var opt = sample.getValue();
if (opt.isPresent()) {
    System.out.println(opt.get()); // abcd
}
final var sample = new Sample<>(null);

//sample.getValue().get(); // NoSuchElementException: No value present

int hashCode ()

存在する場合は値のハッシュ・コードを返し、値が存在しない場合は0 (zero)を返します。

System.out.println(Optional.empty().hashCode()); // 0

System.out.println(Optional.of(123).hashCode()); // 123

System.out.println("abcd".hashCode()); // 2987074
System.out.println(Optional.of("abcd").hashCode()); // 2987074

void ifPresent (Consumer<? super T> action)

値が存在する場合は、その値で指定されたアクションを実行し、そうでない場合は何もしません。

final var sample = new Sample<>("abcd");

sample.getValue().ifPresent(value -> {
    System.out.println("action : " + value);
});

// 結果
// ↓
//action : abcd
final var sample = new Sample<>(null);

sample.getValue().ifPresent(value -> {
    // 空の場合は呼び出されません。
    System.out.println("action : " + value);
});

// 結果
// ↓
//<なにも表示されません>

void ifPresentOrElse (Consumer<? super T> action, Runnable emptyAction)

値が存在する場合は、指定されたアクションを値とともに実行し、そうでない場合は空のベースのアクションを実行します。

final var sample = new Sample<>("abcd");

sample.getValue().ifPresentOrElse(value -> {
    System.out.println("action : " + value);
}, () -> {
    System.out.println("emptyAction!");
});

// 結果
// ↓
//action : abcd
final var sample = new Sample<>(null);

sample.getValue().ifPresentOrElse(value -> {
    System.out.println("action : " + value);
}, () -> {
    System.out.println("emptyAction!");
});

// 結果
// ↓
//emptyAction!

boolean isEmpty ()

値が存在しない場合はtrue、それ以外の場合falseを返します。

final var sample = new Sample<>("abcd");

if (sample.getValue().isEmpty()) {
    System.out.println("empty!");
} else {
    System.out.println("present!");
}

// 結果
// ↓
//present!
final var sample = new Sample<>(null);

if (sample.getValue().isEmpty()) {
    System.out.println("empty!");
} else {
    System.out.println("present!");
}

// 結果
// ↓
//empty!

boolean isPresent ()

値が存在する場合はtrueを返し、そうでない場合はfalseを返します。

final var sample = new Sample<>("abcd");

if (sample.getValue().isPresent()) {
    System.out.println("present!");
} else {
    System.out.println("empty!");
}

// 結果
// ↓
//present!
final var sample = new Sample<>(null);

if (sample.getValue().isPresent()) {
    System.out.println("present!");
} else {
    System.out.println("empty!");
}

// 結果
// ↓
//empty!

<U> Optional<U> map (Function<? super T,? extends U> mapper)

値が存在する場合は、与えられたマッピング関数をその値に適用した結果を(ofNullable(T)のように)記述するOptionalを返します。それ以外の場合は、空のOptionalを返します。

final var sample = new Sample<>("abcd");

final var ret = sample.getValue().map(s -> {
    System.out.println("map : " + s);
    return s.toUpperCase();
});

System.out.println("ret : " + ret);

// 結果
// ↓
//map : abcd
//ret : Optional[ABCD]

final var ret2 = sample.getValue().map(s -> {
    System.out.println("map : " + s);
    return null;
});

System.out.println("ret : " + ret2);

// 結果
// ↓
//map : abcd
//ret : Optional.empty
final var sample = new Sample<>(255);

final var ret1 = sample.getValue().map(i -> {
    System.out.println("map : " + i);
    return i * 2;
});

System.out.println("ret : " + ret1);

// 結果
// ↓
//map : 255
//ret : Optional[510]

final var ret2 = sample.getValue().map(i -> {
    System.out.println("map : " + i);
    return "0x" + Integer.toHexString(i);
});

System.out.println("ret : " + ret2);

// 結果
// ↓
//map : 255
//ret : Optional[0xff]
final var sample = new Sample<String>(null);

final var ret = sample.getValue().map(s -> {
    // 空の場合は呼び出されません。
    System.out.println("map : " + s);
    return s.toUpperCase();
});

System.out.println("ret : " + ret);

// 結果
// ↓
//ret : Optional.empty

static <T> Optional<T> of (T value)

指定された非null値を記述するOptionalを返します。

final var opt1 = Optional.of(123);
System.out.println(opt1); // Optional[123]

final var opt2 = Optional.of("abc");
System.out.println(opt2); // Optional[abc]

//Optional.of(null); // NullPointerException

static <T> Optional<T> ofNullable (T value)

非nullならば、指定された値を記述するOptionalを返し、それ以外の場合は空のOptionalを返します。

final var opt1 = Optional.ofNullable(123);
System.out.println(opt1); // Optional[123]

final var opt2 = Optional.ofNullable("abc");
System.out.println(opt2); // Optional[abc]

final var opt3 = Optional.ofNullable(null);
System.out.println(opt3); // Optional.empty

Optional<T> or (Supplier<? extends Optional<? extends T>> supplier)

値が存在する場合は値を記述するOptionalを返し、そうでない場合は供給関数によって生成されたOptionalを返します。

final var sample = new Sample<>("abcd");

final var ret = sample.getValue().or(() -> {
    // 値が存在する場合は呼び出されません。
    System.out.println("or action!");
    return Optional.of("XYZ");
});

System.out.println("ret : " + ret);

// 結果
// ↓
//ret : Optional[abcd]
final var sample = new Sample<>(null);

final var ret = sample.getValue().or(() -> {
    System.out.println("or action!");
    return Optional.of("XYZ");
});

System.out.println("ret : " + ret);

// 結果
// ↓
//or action!
//ret : Optional[XYZ]

T orElse (T other)

値が存在する場合は値を返し、そうでない場合はotherを返します。

final var sample = new Sample<>("abcd");

final var ret = sample.getValue().orElse("XYZ");
System.out.println(ret); // abcd
final var sample = new Sample<>(null);

final var ret = sample.getValue().orElse("XYZ");
System.out.println(ret); // XYZ

T orElseGet (Supplier<? extends T> supplier)

値が存在する場合は値を返し、そうでない場合は供給関数によって生成された結果を返します。

final var sample = new Sample<>("abcd");

final var ret = sample.getValue().orElseGet(() -> {
    // 値が存在する場合は呼び出されません。
    System.out.println("or action!");
    return "XYZ";
});

System.out.println("ret : " + ret);

// 結果
// ↓
//ret : abcd
final var sample = new Sample<>(null);

final var ret = sample.getValue().orElseGet(() -> {
    System.out.println("or action!");
    return "XYZ";
});

System.out.println("ret : " + ret);

// 結果
// ↓
//or action!
//ret : XYZ

T orElseThrow ()

値がある場合は値を返し、そうでない場合はNoSuchElementExceptionをスローします。

final var sample = new Sample<>("abcd");

final var opt = sample.getValue();
if (opt.isPresent()) {
    System.out.println(opt.orElseThrow()); // abcd
}
final var sample = new Sample<>(null);

//sample.getValue().orElseThrow(); // NoSuchElementException: No value present

<X extends Throwable> T orElseThrow (Supplier<? extends X> exceptionSupplier)

値が存在する場合は値を返し、そうでない場合は例外を提供する関数によって生成された例外をスローします。

final var sample = new Sample<>("abcd");

final var opt = sample.getValue();
if (opt.isPresent()) {
    System.out.println(opt.orElseThrow(IllegalStateException::new)); // abcd
}
final var sample = new Sample<>(null);

try {
    sample.getValue().orElseThrow(() -> {
        throw new IllegalStateException("optional is empty");
    });
} catch (IllegalStateException e) {
    System.out.println(e);
}

// 結果
// ↓
//java.lang.IllegalStateException: optional is empty

Stream<T> stream ()

値が存在する場合は、その値のみを含む順次Streamを返し、それ以外の場合は空のStreamを返します。

final var sample = new Sample<>("abcd");

final var ret1 = sample.getValue().stream().toList();
System.out.println(ret1); // [abcd]

final var ret2 = sample.getValue().stream().count();
System.out.println(ret2); // 1
final var sample = new Sample<>(null);

final var ret1 = sample.getValue().stream().toList();
System.out.println(ret1); // []

final var ret2 = sample.getValue().stream().count();
System.out.println(ret2); // 0

String toString ()

デバッグに適したこのOptionalの空でない文字列表現を返します。

final var ret1 = Optional.empty().toString();
System.out.println(ret1); // Optional.empty

final var ret2 = Optional.of(123).toString();
System.out.println(ret2); // Optional[123]

final var ret3 = Optional.of("abc").toString();
System.out.println(ret3); // Optional[abc]

関連記事

ページの先頭へ