概要
Java 1.8より導入されたjava.util.Optionalクラスのおさらいメモです。
環境
- Windows 10 Professional
- Oracle JDK 9.0.4
- Oracle JDK 10.0.1
参考
- [Oracle JDK 9ドキュメント] (https://docs.oracle.com/javase/jp/9/index.html)
- [Oracle JDK 10ドキュメント] (https://docs.oracle.com/javase/jp/10/index.html)
[Optional<T> - Java 1.8] (https://docs.oracle.com/javase/jp/8/docs/api/java/util/Optional.html)
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] (https://docs.oracle.com/javase/jp/9/docs/api/java/util/Optional.html)
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] (https://docs.oracle.com/javase/jp/10/docs/api/java/util/Optional.html)
- モジュール: java.base
- パッケージ: java.util
orElseThrow
Optionalオブジェクトが保持する値を返します。保持する値がnullの場合はNoSuchElementExceptionをスローします。この動作はgetメソッドと同じです。
このため、Java 1.8からある同じメソッド名のorElseThrowのバリエーションの追加というよりも
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)
throws X extends Throwable
getメソッド名から曖昧さを取り除いたgetメソッドの代わりになるメソッドという感じです。
public T get()
orElseThrowはメソッド名から例外がスローされ得ることがわかります。
public T orElseThrow()
[Java 11で追加されたAPI] ()
isEmpty
public boolean isEmpty()
値が存在しない場合にtrueを返します。
[Java 12で追加されたAPI] (https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/Optional.html)
追加されたAPIはありません。
[Java 13で追加されたAPI] (https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/Optional.html)
追加されたAPIはありません。
[Java 14で追加されたAPI] (https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/Optional.html)
追加されたAPIはありません。
その他のおさらいメモ
- [Java NIO2のおさらいメモ] (https://qiita.com/rubytomato@github/items/6880eab7d9c76524d112)
- 2017年08月15日
- [クラス java.util.Objectsのおさらいメモ] (https://qiita.com/rubytomato@github/items/ba38877ed5a00dd24f16)
- 2017年08月25日
- [Java Collections Frameworkのおさらいメモ] (https://qiita.com/rubytomato@github/items/554095ae21a2c36f131a)
- 2017年08月30日
- [パッケージ java.time.temporal のおさらいメモ] (https://qiita.com/rubytomato@github/items/e9325dd46aa11f1b8e2e)
- 2018年01月30日