Java

クラス java.util.Optionalのおさらいメモ

概要

Java 1.8より導入されたjava.util.Optionalクラスのおさらいメモです。

環境

  • Windows 10 Professional
  • Oracle JDK 9.0.4
  • Oracle JDK 10.0.1

参考

Optional<T> - Java 1.8

empty / of / ofNullable

いずれもstaticメソッドです。Optionalはpublicなコンストラクタを持たないのでOptionalオブジェクトを生成するにはこれらのメソッドを利用します。

empty

null値を持つOptionalオブジェクトを返します。

Optional<String> empty = Optional.empty();
empty.isPresent();
// false

empty.orElse("other");
// other

empty.get();
// java.util.NoSuchElementException: No value present

of

非null値を持つOptionalオブジェクトを返します。

String str = "nonNull";
Optional<String> nonNullString = Optional.of(str);
nonNullString.isPresent();
// true

nonNullString.get();
// result : nonNull

ofにnullなオブジェクトを渡すと例外がスローされます。

String str = null;
Optional.of(str);
//  java.lang.NullPointerException

ofNullable

nullかもしれない値(nullable)を持つOptionalオブジェクトを返します。

String str = null;
Optional<String> nullableString = Optional.ofNullable(str);
nullableString.isPresent();
// false

nullableString.orElse("other");
// other

get / isPresent

get

Optionalオブジェクトが保持する値を返します。保持する値がnullの場合はNoSuchElementExceptionがスローされます。

String str = "apple";
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.get();
// apple
String str = null;
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.get();
// java.util.NoSuchElementException: No value present

isPresent

Optionalオブジェクトが保持する値が非nullの場合はtrue、nullの場合はfalseを返します。

String str = "apple";
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.isPresent();
// true
String str = null;
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.isPresent();
// false

orElse / orElseGet / orElseThrow

orElse

Optionalオブジェクトが保持する値を返します。保持する値がnullの場合は指定した値を返します。(nullも可)

String str = "nonNull";
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.orElse("other");
// nonNull
String str = null;
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.orElse("other");
// other

nullableString.orElse(null);
// null

orElseGet

Optionalオブジェクトが保持する値を返します。保持する値がnullの場合は指定したSupplierの結果を返します。
Supplierがnullを返す場合はnullが返ります。

String str = "nonNull";
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.orElseGet(() -> "other");
// nonNull
String str = null;
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.orElseGet(() -> "other");
// other

nullableString.orElseGet(() -> null);
// null

orElseThrow

Optionalオブジェクトが保持する値を返します。保持する値がnullの場合は指定した例外がスローされます。

String str = null;
Optional<String> nullableString = Optional.ofNullable(str);

nullableString.orElseThrow(RuntimeException::new);
// java.lang.RuntimeException

ifPresent

Optionalオブジェクトが保持する値が非nullの場合、その値で引数に指定するConsumerの処理ブロックを実行します。
Optionalオブジェクトが保持する値がnullの場合は例外はスローされず、またなにも実行されません。

Optional<Employee> employee = Optional.ofNullable(new Employee(1L, "john"));
employee.ifPresent((e) -> {
    e.setName(e.getName().toUpperCase());
    System.out.println(e);
    // Employee{id=1, name='JOHN'}
});

filter / map / flatMap

filter

Optionalオブジェクトが保持する値が非nullの場合、その値で引数に指定するPredicateの処理ブロックを実行します。

Optional<String> nullableString = Optional.ofNullable("banana");

Optional<String> filtering = nullableString.filter(str -> str.length() > 5);
filtering.isPresent();
// true

filtering.orElse("other");
// banana

Optionalオブジェクトが保持する値がnullの場合、またはPredicateの処理ブロックがfalseを返す場合は空のOptionalが返ります。

Optional<String> nullableString = Optional.ofNullable("apple");
// Optional<String> nullableString = Optional.ofNullable(null);

Optional<String> filtering = nullableString.filter(str -> str.length() > 5);
filtering.isPresent();
// false

filtering.orElse("other");
// other

map

Optionalオブジェクトが保持する値が非nullの場合、その値で引数に指定するFunctionの処理ブロックを実行します。

Optional<String> nullableString = Optional.ofNullable("apple");
Optional<Integer> mapping = nullableString.map(str -> str.length());

mapping.isPresent();
// true

mapping.orElse(0);
// 5

Optionalオブジェクトが保持する値がnullの場合、またはFunctionの処理ブロックがnullを返す場合は空のOptionalが返ります。

Optional<String> nullableString = Optional.ofNullable(null);
Optional<Integer> mapping = nullableString.map(str -> str.length());

mapping.isPresent();
// false

mapping.orElse(0);
// 0

flatMap

Optionalオブジェクトが保持する値が非nullの場合、その値で引数に指定するFunctionの処理ブロックを実行します。
mapとの違いはFunctionがOptionalオブジェクトを返す点です。

mapに指定するFunctionはT型を取りU型を返します。

Function<? super T,? extends U> mapper

flatMapに指定するFunctionはT型を取りOptional型を返します。

Function<? super T,Optional<U>> mapper
Optional<Long> optId = Optional.of(1L);
Optional<String> optName = Optional.of("john");

Optional<Employee> result = optId.flatMap(id -> optName.flatMap(name -> Optional.of(new Employee(id, name))));

result.isPresent();
// true

result.orElse(null);
// Employee{id=1, name='john'}

Optionalオブジェクトが保持する値がnullの場合は空のOptionalを返します。

Optional<Long> optId = Optional.of(1L);
Optional<String> optName = Optional.ofNullable(null);

Optional<Employee> result = optId.flatMap(id -> optName.flatMap(name -> Optional.of(new Employee(id, name))));

result.isPresent();
// false

result.orElse(null);
// null

Optionalを返すFunctionをmapで使うと戻り値が期待しない型になってしまいます。

Optional<Optional<String>> nullableName = employee.map(emp -> Optional.ofNullable(emp.getName()));

Java 9で追加されたAPI

ifPresentOrElse

ifPresentのバリエーションが増えました。
Optionalオブジェクトが保持する値がnullの場合、引数に指定するRunnableの処理ブロックが実行されます。

Optional<Employee> employee = Optional.ofNullable(null);

employee.ifPresentOrElse((e) -> {
    e.setName(e.getName().toUpperCase());
    System.out.println(e);
},
() -> {
    System.out.println("empty action");
    // empty action
});

or

Optionalオブジェクトが保持する値がnullの場合、引数に指定するSupplierが生成したOptionalオブジェクトを返します。
Supplierがnullを返すと例外がスローされます。

String str = null;
Optional<String> nonNullString = Optional.ofNullable(str).or(() -> Optional.of("nonNull"));

nonNullString.isPresent();
// true

nonNullString.get();
// nonNull

stream

Optionalオブジェクトが保持する値が非nullの場合はその値だけを持つstreamを返し、nullの場合は空のstreamを返します。

List<Optional<String>> list = List.of(
    Optional.of("a"),
    Optional.of("b"),
    Optional.of("c"),
    Optional.empty(),
    Optional.of("e"),
    Optional.empty(),
    Optional.of("g")
);

list.stream().filter(Optional::isPresent).map(Optional::get).forEach(System.out::println);
// a
// b
// c
// e
// g

// streamを使う場合
list.stream().flatMap(Optional::stream).forEach(System.out::println);
// a
// b
// c
// e
// g

Java 10で追加されたAPI

  • モジュール: java.base
  • パッケージ: java.util

orElseThrow

Optionalオブジェクトが保持する値を返します。保持する値がnullの場合はNoSuchElementExceptionをスローします。この動作はgetメソッドと同じです。
このため、Java 1.8からある同じメソッド名のorElseThrowのバリエーションの追加というよりも

java1.8_orElseThrowのシグネチャ
public <X extends Throwable> T orElseThrow​(Supplier<? extends X> exceptionSupplier)
    throws X extends Throwable

getメソッド名から曖昧さを取り除いたgetメソッドの代わりになるメソッドという感じです。

java1.8_getのシグネチャ
public T get()

orElseThrowはメソッド名から例外がスローされ得ることがわかります。

java10_orElseThrowのシグネチャ
public T orElseThrow()

その他のおさらいメモ