Java8 の Optional とガード節

公開日: : 最終更新日:2015/01/12 Java ,

メソッドの冒頭で条件チェックを行い、条件を満たしていない場合はさっさと return してしまう「ガード節」を取り入れる癖が付いている。

Java8 から Optional が導入されたが、この Optional を引数で受け取るメソッドの場合、ガード節をどうやって書けばいいのかしっくり来ていない。

Optional に触れる機会を増やしてきたことで、何かヒントになりそうなコードが書けるようになってきたのでメモしておく。

icatch_4610898091

photo credit: Niccolò Caranti via photopin cc

目次

1. ガード節とは

新装版 リファクタリング―既存のコードを安全に改善する―(ボクが当時読んだのは旧版)を読んでガード節を知った。

優れた技術書をいくら読んでもそれを活かせないようでは意味がないので、「さらっと取り入れられそうなリファクタリングはどれか?」と考えたときに目にとまったのが「ガード節」だった。

ガード節については Strategic Choice さんから引用しておく。

if-then-else構文を使う場合、if/thenの分岐先とelseの分岐先には同等のウェイトを置いています。両方の分岐先が同じように実行され、重要だということを読者に伝えます。それに対し、ガード節は「これはまれなケースで、発生した場合には何かちょっとしたことを行って外に出る」ということを明確に表現することができます。

Replace Nested Conditional with Guard Clauses – Strategic Choice

2. Optional 型を受け取らないメソッドの場合

Java7 以前でのガード節。

null チェックをして、null なら return してしまう。早い段階で return することで、その後は null の可能性を排除してコードが読める。

Hoge hoge = getHoge(key);
if(Objects. isNull(hoge)) {
    return "not_found"; // 取得できなかったので "not_found" を返す
}

// hoge が null じゃなかった場合の処理
doSomething();
return "success"; // `doSomething()` をしたあとは "success" を返す

コードは変数の値や処理の流れなどいろいろ覚えながら読む。ガード節を取り入れることで、覚える数が減ったり可能性が排除できるので読みやすくなるので個人的にとても気に入っている。

2-1. 備考1

hoge が null であっては困るとか、そもそも null だとバグという場合は Objects.requireNonNull(hoge) を使って引数を確認する方法もある。

このメソッドを使った場合、null だと NullPointerException が発生するようになっている。1行で書けるから記述量が減るが、 NullPointerException なのでパッと見てすぐに不正な引数だったことが分かりにくいと思っている。

2-2. 備考2

ここでは例として null チェックを取り上げているが、当然 null 以外の条件チェックもガード節に含まれる。

3. Optional を受け取っただけのしっくり来ない書き方

Optional は使っているが、Java7 以前と同じ書き方。

getHoge() の戻り値が Optional になっただけで、ガード節の書き方自体は Java7 以前と同じというちょっとアレな書き方。

Optinal<Hoge> hoge = getHoge(key);
if(!hoge.isPresent()) {
    return "not_found"; // 取得できなかったので "not_found" を返す
}

// hoge が null じゃなかった場合の処理
doSomething();
return "success"; // `doSomething()` をしたあとは "success" を返す

全然それっぽくないし、こういうコードを書いてはいけないんだろうと思っている。

4. 今のところ Optional を使った場合はこうやって書くんだろうと思っている書き方

こんな感じにしか書けないんじゃないかと思っているから受け入れざるを得ない状態になっている。まだ馴染めない。

Optional<String> result = getHoge(key).map(h -> {
    // hoge が null じゃなかった場合の処理
    doSomething();
    return "success"; // `doSomething()` をしたあとは "success" を返す
});
return result.orElse("not_found"); // 取得できなかったので "not_found" を返す

まだ馴染めないのは、「最初にガツンと return で跳ね返すのがガード節だ!」っという固定概念がジャマしているからなのか、まだラムダ式に馴染んでいないからなのか。

4-1. 備考3

上記の例では “success” とか “not_found” といった値を返したかったので Optional#map() を使っている。戻り値を返す必要がない場合は Optional#ifPresent() を使う。

いずれにしても if 文を使って条件分岐するのではなく、ラムダ式を使って「条件を満たした場合の処理」を繋げる。

これまでは return していたから(エディタがハイライトしてくれることもあって)見た目に分かりやすかったが、これからはインデントがそれに代わることになるのかもしれない。

5. 更新履歴

  • 2014/10/17
    • 初版作成
  • 2015/01/11
    • 文言を修正

6. この記事の内容について

この記事は Javaプログラマーなら習得しておきたい Java SE 8 実践プログラミング を読みながら個人的にまとめたことをメモした内容になっています。

調べ物から記事作成までの全て作業はプライベートな時間に行ったものであり、所属組織のリソースは消費していません。また、記事のアイデアも所属組織に由来していません。

記事の内容が必ずしも正しかったり、最新ではないおそれがあります。参考にされる分には構いませんが、記事の内容を取り入れたことによって発生した損害などの責任は負いません。ご利用は自己判断でお願いいたします。

Javaプログラマーなら習得しておきたい Java SE 8 実践プログラミング

  • 著者Cay S. Horstmann
  • 価格¥ 3,024(2014/10/17 時点)
  • 出版日2014-09-22
  • 商品ランキング24027 位
  • 大型本264 ページ
  • ISBN-104844336673
  • 出版社インプレス

Googleアドセンス用(PC)

  • このエントリーをはてなブックマークに追加
  • follow us in feedly

関連記事

icatch-zip_524574337_mini-thumbnail

Java でファイルが1つだけ圧縮された zip を解凍するサンプル

ファイルが1つだけ圧縮された zip を解凍するサンプルです。 単一ファイルが圧縮された zip

記事を読む

icatch-thumbnail

レスポンスにサムネイル画像を返す API のサンプル

今回は直接 ImageMagick は関係ありませんが、また画像ネタです。この辺りのことを仕事で扱っ

記事を読む

no image

Spark を使って JSON を返すシンプルな API を書いてみた

必要に迫られてモックの API を作成することになった。 大した工数を割けないので使ったことのある

記事を読む

medium_2055608272

指定した年月の日付を Calendar オブジェクトの一覧で取得する

小ワザです。 業務で、指定した年月の日付を Calendar オブジェクトの一覧で取得する必要があり

記事を読む

no image

ファイルに関するユーティリティ

ファイルに関するスニペットをいくつか書いた。いつかコピペする日が来ると思うのでメモしておく。 作成

記事を読む

no image

google-gson でシリアライズ・デシリアライズしたサンプル

これまで Java で JSON を扱うときは JSONIC を使っていたが、google-gson

記事を読む

icatch-3361b5e1-resized

Optional型の変数にget()とifPresent()は使わない

Java8 から導入された Optional を勉強するため、過去にプライベートで書いたコードに O

記事を読む

no image

ディレクトリに関するユーティリティ

ディレクトリに関するスニペットをいくつか書いた。いつかコピペする日が来ると思うのでメモしておく。

記事を読む

medium_182531101

ClassLoader を使って getResourceAsStream で取得したファイルを UTF-8 で読み込む

よく使う割には覚えられず毎回調べている気がするので備忘録としてメモしておきます。 文字コードを指定し

記事を読む

no image

Exec Maven Plugin で maven コマンドでアプリを起動する

packaging タグに "jar" を指定した Maven プロジェクトをコマンドラインから起動

記事を読む

Googleアドセンス用(PC)

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


4 − = 零

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Googleアドセンス用(PC)

icatch-jersey_multi_pathparams
Jerseyの@PathParamはスラッシュの間に複数指定できる

http://hoge-api/user/{id}.{format}

icatch-vagrant_box_customize
VagrantのBoxファイルをカスタマイズして独自のBoxファイルを作成する

配布されている Vagrant の Box ファイルを使って検証環境を

icatch-2015-006-1
バリデーションチェックにJava8のOptionalを使ってスマートに書く(自分比)

Web アプリのバリデーションチェックにアノテーションを使うことが増え

icatch-2015-005-1
ユニットテストの偏りを防ぐ命名規則の付け方

ユニットテスト名に以下の命名規則を付けるようにして二ヶ月ぐらい経った。

icatch-2015-004-1
Vagrantで起動したCentOS上のOctopressをホストOSから確認する設定

タイトルの通りだが、Vagrant を使って起動した CentOS に

→もっと見る

PAGE TOP ↑