Javaでnullを安全に扱う − Optionalの使い方

Javaでnullを安全に扱う − Optionalの使い方

目次

Optionalとは

Javaでは値のない状態のことをnullと言いますが、nullが原因で意図しないエラーが発生することも多いです。そのため、エラーを未然に防ぐためにif文を利用してnullチェックの処理を書く必要がありました。

Java8から java.util.Optionalクラスが導入されました。Optionalを使うと、値がnullであるかどうかを簡潔に書くことができます。if文のブロックを書かなくてもnullチェックが記述する事ができます。

  • Optionalはnullかもしれないと伝えるもの

また、「値が入っていない場合」という処理を明示的に記述することが出来るため、ifによるnullチェック時のミスを減らすことも可能になり、プログラムの堅牢性が向上します。

オブジェクトの生成

of(nullでない値専用 )

非null値を持つOptionalオブジェクトを返します。 ofにnullなオブジェクトを渡すと例外がスローされます。

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

nonNullString.isPresent();
// true

nonNullString.get();
// result : nonNull

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

ofNullable(nullかもしれない )

ofNullableメソッドの引数にはnullの可能性があるオブジェクト名を指定します。ofNullableメソッドは引数がnullの場合に、Optional型の空のオブジェクトを返します。引数がnull以外の場合は、指定された値を記述するOptional型のオブジェクトを返します。

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

nullableString.isPresent();
// false

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

empty (空の Optional オブジェクト)

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

Optional<String> value = Optional.empty();

empty.isPresent();
// false

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

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

値を取り出す

get

Optionalオブジェクトが保持する値を返します。値がない場合は、NoSuchElementExceptionがthrowされます

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

nullableString.get();
// apple

String str2 = null;
Optional<String> nullableString2 = Optional.ofNullable(str2);

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

値をチェックする

isPresent

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

String str = "hoge";
Optional<String> value = Optional.of(str);
if(value.isPresent()) {
    System.out.println("値があります");
}

isEmpty

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

String str = null;
Optional<String> value = Optional.of(str);
if(value.isEmpty()) {
    System.out.println("値がnullです");
}

ifPresentOrElse

ifPresentOrElseメソッドではnullでない場合の処理を第1引数に指定します。nullの場合の処理を第2引数に指定します。

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

orElse

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

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

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

String str2 = null;
Optional<String> nullableString2 = Optional.ofNullable(str2);

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

orElseGet

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

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

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

String str2 = null;
Optional<String> nullableString2 = Optional.ofNullable(str2);

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

orElseThrow

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

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

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

値を加工する

map

値がある場合に、引数で指定した処理を実行して加工した値の Optional オブジェクトを返却します。

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

mapping.isPresent();
// true

mapping.orElse(0);
// 5

値変換の結果がOptionalの場合に便利なflatMap

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'}

条件にマッチした値だけにする

filter

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

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

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

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

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

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

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

値でStreamを作るstream

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

コメントを残す

入力エリアすべてが必須項目です。メールアドレスが公開されることはありません。

内容をご確認の上、送信してください。