Optionalクラスとは?
メソッドの処理結果を扱うためのクラスです。
処理結果の正常・異常にかかわらず同じ型を扱うことができます。
Java SE 8で導入されました。
導入の背景
従来、メソッドの設計時には、処理結果に異常があれば例外をスローするようにしていました。この異常時の処理によって、突然catchブロックに制御が遷移するので、コードの可読性を下げていました。Optionalクラスの導入によって、例外処理に関するコードを減らすことができ、その結果コードの可読性を上げることができるようになりました。
改善例
以下はOptionalクラス導入前のソースです。このソースには課題が4つあります。
- インデックスが、配列の要素数を超えてしまうことがある
- 配列の要素がnullである可能性があるため、戻り値を受け取った側でnullの確認をしなければNullPointerExceptionが発生する
- 引数の配列が参照型であるため、配列への参照ではなくnullが渡される可能性がある
- スローされてくるIllegalArgumentExeptionは非検査例外あるため、例外処理が無視される可能性がある
public class OldTest {
public static void main(String[] args) {
try {
// 課題1の箇所
String result = getFromArray(new String[]{"A", "B", null}, 3};
// 課題2の箇所
if (result == null) {
System.out.println("empty");
return;
}
System.out.println(result);
} catch (IllegalArgumentException e) {
System.out.println("exception");
}
}
// 課題3の箇所
private static <T> T getFromArray(T[] array, int index) {
if (array == null) {
throw new IllegalArgumentException();
}
try {
return array[index];
} catch (ArrayIndexOutOfBoundsException e) {
// 課題4の箇所
throw new IllegalArgumentException();
}
}
}
Optionalクラスを利用して、上記のコードを以下のように改善できます。
import java.util.Optional;
public class Test {
public static voi main(String[] args) {
Optional<String> result = getFromArray(new String[]{"A", "B", null}, 3};
if (result.isEmpty()) {
System.out.println("empty");
return;
}
System.out.println(result.get());
// 課題4の改善: 例外ではなく戻り値を戻すため、例外処理そのものが不要
private static <T> Optional<T> getFromArray(T[] array, int index) {
if (array == null) {
// 課題3の改善: nullチェックを行い、からのOptionalのインスタンスへの参照を戻す
return Optional.empty();
}
try {
// 課題2の改善: ofNullableメソッドは引数の値がnullだった場合、空のOptionalのインスタンスへの参照を戻す
return Optional.ofNullable(array[index]);
} catch (ArrayIndexOutOfBoundsException e) {
// 課題1の改善: 例外が発生した時は空のOptionalのインスタンスへの参照を戻す
return Optional.empty();
}
}
}
メソッド一覧
インスタンスを生成する
メソッド | 説明 |
---|---|
empty() | 空のOptionalのインスタンスを生成し、参照を戻す |
of(T value) | null以外の値を持ったOptionalのインスタンスを生成し、参照を戻す nullを渡すとNullPointerExceptionが発生する |
ofNullable(T value) | 値が有るか、nullの場合は、空のOptionalのインスタンスを生成し、参照を戻す |
値を取得する
メソッド | 説明 |
---|---|
get() | 値が有る場合はその値を、それ以外の場合はNoSuchElementExceptionをスローする |
値の有無を確認する
メソッド | 説明 |
---|---|
isPresent() | 値が有る場合はtrue、無い場合はfalseを戻す |
isEmpty() | 値が無い場合はtrue、有る場合はfalseを戻す |
値を加工する
メソッド | 説明 |
---|---|
map(Function<? super T,? extends U> mapper) | 値が有る場合は、引数に渡してラムダ式を実行して、その結果を持ったOptionalを戻す |
flatMap(Function super T,Optional> mapper) | 値が有る場合は、引数に渡してラムダ式を実行し、値が無い場合は場合は空のOptionalを戻す |
値の有無で別々の処理をする
メソッド | 説明 |
---|---|
orElse(T other) | 値が有る場合はその値を、無い場合は引数で渡した代替値を戻す |
orElseGet(Supplier<? extends T> other) | 値が有る場合はその値を、無い場合は引数のラムダ式を実行してその結果を戻す |
ifPresent(Consumer<? super T> consumer) | 値が有る場合は、引数に渡してラムダ式を実行する |
ifPresentOrElse(Consumer super T> action, Runnable emptyAction) | 値が有る場合は、第1引数で指定したラムダ式を実行し、値が無い場合は第2引数で指定したラムダ式を実行する |
参考文献
徹底攻略Java SE 11 Gold問題集