Skip to content

Instantly share code, notes, and snippets.

@asufana
Last active December 14, 2015 03:01
Show Gist options
  • Save asufana/a578b102d6af6f65310f to your computer and use it in GitHub Desktop.
Save asufana/a578b102d6af6f65310f to your computer and use it in GitHub Desktop.
Java8 Optional

Java8 Optional

Null参照の発明は10億ドルの損失

2009年のカンファレンスでNull参照を発明したことについて謝罪している。[10][11] それは10億ドルにも相当する私の誤りだ。null参照を発明したのは1965年のことだった。当時私はオブジェクト指向言語 (ALGOL W) における参照のための包括的型システムを設計していた。目標はコンパイラでの自動チェックで全ての参照が完全に安全であることを保証することだった。しかし、私は単にそれが容易だというだけで、無効な参照を含める誘惑に抵抗できなかった。これは後に数え切れない過ち、脆弱性、システムクラッシュを引き起こし、過去40年間で10億ドル相当の苦痛と損害を引き起こしたとみられる。 http://goo.gl/SjpucB

基本的なルール

isPresent は使わない

nullチェックしているのと変わらない

if(product.isPresent()) {
    return product.price();
} else {
    return 0;
}

orElse, orElseThrow を使おう

nullチェックではなく、null時の振る舞いを記述する

//値がなければデフォルト値を返す
return product.orElse(0);

//値がなければ例外
return product.orElseThrow(() -> new RuntimeException("金額未設定"));

get は使わない

値がないと NoSuchElementException がスローされる

return product.get();

Optional何が便利なの?

渡された値がnullな場合があることを意識させられていない?

Java8まではnullを意識せざるを得ない

public boolean validatedZipFormat(String zip){
    //引数のnullチェックしないとね
    return isNotEmpty(zip)
        && zip.matches("^[0-9]{3}-[0-9]{4}$")

Java8からはnullを意識しなくてよい

public boolean validateZipFormat(String zip){
    return Optional.ofNullable(zip)
                   .filter(num -> num.matches("^[0-9]{3}-[0-9]{4}$")) //matchしたらmatch文字列が返却され、matchしなければnull
                   .isPresent();
}

戻り値がnullな場合があることを意識させられていない?

Java8まではnullを意識せざるを得ない

@Test
public void beforeJava8() throws Exception {
    final String nullかも = "";
    assertThat(someFunction(nullかも), is(nullValue()));
}

//なんらかの関数
private String someFunction(final String str) {
    //こう書きたい、でもsomeNullableFuction()がnullを返却した場合には、NullPointerException
    //return someNullableFuction2(str).toUpperCase();
    
    //仕方ないのでnullチェックする
    final String str2 = someNullableFuction(str);
    return isNotEmpty(str2) ? str2.toUpperCase() : null;
}

//null返却もあり得る関数
private String someNullableFuction(final String str) {
    return isEmpty(str) ? null : str;
}

Java8からは(Optionalの中では)nullを意識しなくてよい

@Test
public void afterJava8() throws Exception {
    final String nullかも = "";
    assertThat(someOptionalFunction(nullかも), is(nullValue()));
}

//なんらかの関数
private String someOptionalFunction(final String str) {
	//Optionalの中で処理する
    return Optional.ofNullable(str)
                   .map(st -> someNullableFuction(st)) //emptyなOptionalが返却される
                   .map(st -> st.toUpperCase()) //NullPointerExceptionが発生しない
                   .orElse(null);
}

//null返却もあり得る関数
private String someNullableFuction(final String str) {
    return isEmpty(str) ? null : str;
}

Optionalの中ではnullを意識しなくて良いというは、連続する処理がすべてOptionalのコンテキストを保っているため。

コンテキストを保ったまま、処理を続けられる仕組みをモナドという。 モナドに関しては後日。

Filter

何かの条件で抽出して元の値を返す

@Test
public void testFilter() throws Exception {
    final Integer empId = 444;
    final Predicate<Integer> 特殊なひとたち = id -> id >= 1000 && id < 2000;
    assertThat(特定社員かどうか(empId, 特殊なひとたち), is(false));
}

//特定の社員かどうかをフィルタする関数
private boolean 特定社員かどうか(final Integer empId, final Predicate<Integer> predicate) {
    return Optional.ofNullable(empId)
                   .filter(predicate)
                   .isPresent();
}

Map

何か処理して戻り値を返す

String str = "nullかもしれない文字列"
Integer length = Optional.ofNullable(str)
                         .map(s -> s.length())
                         .orElse(0);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment