[JavaSE8 Goldへの道] その9 Optionalクラス

2018年4月16日月曜日

Java JavaSE8Gold

t f B! P L C
JavaSE8 Goldへの道(Upgrade to Java SE 8 Programmer 1Z0-810 試験対策)9回目です。

一連の記事は「JavaSE8Gold」ラベルを付けていきます。

今回はOptionalクラスです。


Optional<T>クラス

java.util.Optional<T>クラスは、nullかもしれない値を格納するコンテナクラスです。

Optionalインスタンスの生成

コンストラクタは利用できません。必ずファクトリメソッドを使います。
//空のOptionalを生成
Optional<String> str = Optional.empty();

//nullでない値で生成
//※nullを渡すとNullPointerException
Optional<String> optStr = Optional.of("test");

//nullかもしれない値で生成
String str = null;
Optional<String> optStr = Optional.ofNullable(str);

2つめのOptional#ofメソッドでは、nullを渡すとNullPointerExceptionがスローされます。
したがって基本はemptyofNullableメソッドで生成することになると思います。

Optionalから値の取得

値の取得はいろいろな方法があります。
//単に取得
//※中身がnullだとNoSuchElementException
String str = op.get();

//nullの場合渡した値を返す
String str = op.orElse("default");

//nullの場合渡したラムダ式(Supplier)の結果を返す
String str = op.orElseGet(() -> "default");

//nullの場合渡したラムダ式(Supplier)が返す例外をスローする
String str = op.orElseThrow(() -> new RuntimeException("ぬるぽ"));
1つ目はもし中身がnullの場合NoSuchElementExceptionがスローされるので、あまり出番はないと思います。

2つ目のorElseメソッドはnullを指定することもできます。

3つ目のorElseGetメソッドではラムダ式を渡せるので、もっと複雑な生成ロジックやを使うことができます。
(例えば文字列連結などをする場合、nullのときしか評価されないのでパフォーマンスへの影響が少なくなります)

4つ目のorElseThrowは中身がnullの場合なにか別の例外をスローしたい場合に使えます。

その他判定など

他に判定用のメソッドもあります。
//中身が存在するかどうか
boolean present = op.ifPresent();

//中身が存在する場合、ラムダ式(Consumer)を実行する
op.isPresent(s -> System.out.println(s));

1つ目のifPresentメソッドは要するにobj != nullと同じなので、Optionalを使う意味がありません。
したがって2つ目のisPresentメソッドが最も基本の使い方になると思います。

なにかメソッドを設計したときに、nullが返される可能性がある場合はOptional型にしておくと、使う側で工夫が可能になります。
・・・とはいえ、JavaAPIでも全てのnullを返す可能性があるメソッドがOptionalに置き換わったわけではないので、まだまだnullチェックが全く必要なくなったわけではありません。


Streamのような操作

※ここから先は試験範囲外かもしれません。

OptionalにはStreamと同じメソッドもいくつか定義されています。
//値の置き換え(map)
Optional<String> optStr = Optional.ofNullable("value");
Optional<Integer> optInt = optStr.map(s -> s.length());

//値の置き換え+ラップの解除(flatMap)
//なにか処理をしてOptional型を返すfuncメソッドを呼ぶ
Optional<String> optStr = Optional.ofNullable("value");
Optional<String> optStr2 = optStr.flatMap(s -> func(s));

//値のフィルタリング(filter)
Optional<String> optStr = Optional.ofNullable("value");
Optional<String> optStr2 = optStr.filter(s -> s.startWith("a"));

全て中身が存在する場合のみラムダ式が実行されます。存在しない場合空のOptionalが返されるだけです。

Optional#flatMapStreamも同じなのですが、ラムダ式の結果二重にラップされてしまう(Optional<Optional<T>>になってしまう)場合に、ラップを1つ解除してくれます。

Optional#filterはフィルタリングの結果falseになった場合は空のOptionalになります。

Streamの終端操作にはOptionalを返すものがいくつかありますが、これらのメソッドを使うとそのまま延長した処理のように書くことができます。
OptionalStreamの要素が0または1のものとも言えなくもない、と誰かが書いてた気がします。

より詳しくは以下の記事がわかりやすいです。


プリミティブ用Optional

Optionalにもプリミティブ型に対応したものが用意されています。
  • OptionalInt
  • OptionalLong
  • OptionalDouble
getメソッドだけ異なり、getAsXxxとなっています。前述の通り使う機会はないと思いますが。
また、nullがないためofNullableメソッドがありません。

プリミティブ型Streamの終端操作の一部で戻り値として使われています。


と、い、う、わ、け、で

メソッドの戻り値としてnullの可能性があるケースでは積極的に使っていきたいですね。
今後追加されるAPIでも使われると思うので、どのような操作があるかは覚えておきましょう。

今回も以下のサイトとGoldの通常試験の参考書を参考にしています。
一連の記事は「JavaSE8Gold」ラベルを付けていきます。

それではみなさまよきガジェットライフを(´∀`)ノ


▼ブログを気に入っていただけたらRSS登録をお願いします!
▼ブログランキング参加中!応援よろしくお願いします。

ブログ内検索

自己紹介

猫とガジェットが好きなJava屋さんです。うつ病で休職後退職し、1年半の休養後に社会復帰。・・・が、いろいろあって再び退職。さらに1年休職の後に復帰して、なんとかSE続けてます。茶トラのすずと一緒に生活していましたが、2014年9月4日に亡くなって1人に。

より詳細なプロフィールはこちら↓

↓更新情報を受け取るにはフォローをお願いします!

Instagramでフォロー

※ヘッダー及びアイコンで使用しているドロイド君は、googleが作成、提供しているコンテンツをベースに複製したものです。

▼ココナラでメンターサービスを販売しています。招待コード「C3VG3」で1000ポイントもらえます。
▼欲しい物リスト

ブログ アーカイブ

QooQ