① optionalの成り立ち
mapで取り出すとか?、nullを考えさせない実装にできるとか?便利らしいのでoptional
をまとめる。
サクッと調べられる使い方特集よりも、成り立ちとかちょっとした時代背景から説明してくれるORACLEのTechnical Detailsが良さげだったのでこれを読んでみる。調べて軽く見たところ記事内で参考になりそうなリンクを貼ってくれていたため、記載あった3コンテンツを読んでみる
- Tired of Null Pointer Exceptions? Consider Using Java SE 8’s “Optional”!
- Optionalクラスを意図されたとおりに使うための12のレシピ
- JavaのOptionalクラス:nullポインタ例外を防ぐためのさらに11のレシピ
1. Tired of Null Pointer Exceptions? Consider Using Java SE 8’s “Optional”!
概要
値が無いことを表すことにnull
を使用するべきではない。nullのチェックをいちいち挟まないとコードが書けなくなってしまう。ゴールとしてはnullを意識させないコードの書き方ができるよって話(?)。あとは値があるか確認しながら取り出すときはmap
、ない場合のデフォルト値を入れるならorElse
。Optionalクラス内のOptionalフィールドを取り出す際、mapで取り出すとOptionalで包んだOptionalフィールドを返すため2重にOptionalに包まれていて使いずらい。そんなときはflatmap
を使えば平坦化してくれる。
サンプルコード
全体のコードが載っていなかったため、確認用に書いたもの
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Optional;
public class main {
public static void main(String[] args) {
// Optionalオブジェクトの作成
Optional<Soundcard> sc = Optional.empty();
// 値が存在する場合に何かを行う
// orElse 空の場合の処理
// orElseThrow 空の場合例外を投げる
System.out.println("--- 値が存在する場合に何かを行う ---");
Optional<Soundcard> maybeSoundcard = Optional.empty();
Soundcard soundcardDefault = maybeSoundcard.orElse(new Soundcard("basic_sound_card"));
System.out.println("soundcardDefault : " + soundcardDefault.getName());
Optional<Soundcard> maybeSuperSoundcard = Optional.of(new Soundcard("super_sound_card"));
Soundcard soundcardSuper = maybeSuperSoundcard.orElse(new Soundcard("basic_sound_card"));
System.out.println("soundcardSuper : " + soundcardSuper.getName());
// Soundcard soundcardException = maybeSoundcard.orElseThrow(IllegalAccessError::new);
// filterメソッド
System.out.println("--- filterメソッド ---");
Optional<Usb> maybeUSB = Optional.of(new Usb("3.0"));
maybeUSB.filter(usb -> "3.0".equals(usb.getVersion()))
.ifPresent(usb -> System.out.println("OK. viersion is " + usb.getVersion()));
// mapメソッドを使用した値の抽出と変換
System.out.println("--- mapメソッドを使用した値の抽出と変換 ---");
Usb usb3 = new Usb("3.0");
Optional<Soundcard> optionalSoundcard = Optional.of(new Soundcard(usb3));
// optionalSoundcard.map(Soundcard::getUsb)
// .map(Optional::get)
// .filter(usb -> "3.0".equals(usb.getVersion()))
// .ifPresent(usb -> System.out.println("OK. viersion is " + usb.getVersion()));
Optional<Soundcard> optionalSoundcard2 = Optional.of(new Soundcard(new Usb("3.0")));
optionalSoundcard2.flatMap(Soundcard::getUsb)
.map(Usb::getVersion)
.filter("3.0"::equals)
.ifPresent(usbVersion -> System.out.println("OK. viersion is " + usbVersion));
// flatMapメソッドを使用したOptionalオブジェクトのカスケード
System.out.println("--- flatMapメソッドを使用したOptionalオブジェクトのカスケード ---");
Optional<Computer> optionalComputer = Optional.of(new Computer(Optional.of(new Soundcard(new Usb("3.0")))));
String version = optionalComputer
.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUsb)
.map(Usb::getVersion)
.orElse("UNKNOWN");
System.out.println("optionalComputer of usb version is " + version);
Optional<Computer> optionalComputer2 = Optional.of(new Computer(Optional.of(new Soundcard(Optional.empty()))));
String version2 = optionalComputer2
.flatMap(Computer::getSoundcard)
.flatMap(Soundcard::getUsb)
.map(Usb::getVersion)
.orElse("UNKNOWN");
System.out.println("optionalComputer2 of usb version is " + version2);
}
}
@Getter
class Computer {
private Optional<Soundcard> soundcard;
Computer(Optional<Soundcard> soundcard) {
this.soundcard = soundcard;
}
}
@Getter
class Soundcard {
private Optional<Usb> usb;
private String name;
Soundcard(String name) {
this.name = name;
}
Soundcard(Usb usb) {
this.usb = Optional.of(usb);
}
Soundcard(Optional<Usb> usb) {
this.usb = usb;
}
}
@Getter
@AllArgsConstructor
class Usb {
private String Version;
}