ITの隊長のブログ

ITの隊長のブログです。Rubyを使って仕事しています。最近も色々やっているお(^ω^ = ^ω^)

【PlayFramework】Optional最高ですね!!!!

スポンサードリンク

Null pointer exception

略してぬるぽ(日本だけだけど)

このエラーはほとんどがプログラマの考慮漏れで発生する。だが、我々は人間だ。使い慣れたクラスならまだしも、初めて使うライブラリなどは使ってみてみないとどう動作するかはコードを見ただけで読み取ることは難しいと思う(デキる人は多いと思うけど)

趣味で運用しているアプリケーションで発生するのはまだいいが、仕事中、またはお客様の環境で発生すると本当に面倒なことである。

発生しても、コード上ではどこで発生しているかすぐにつかめないのも問題だと思う。コードの量が多ければ多いほどその作業はもっと辛くなる。

余談だが、Nullを開発したアントニー・ホーアはこう語る。

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

Nullの影響は本当にすごい。(実際調べてはいないけど)

困った人は世界中で何億人といるじゃないだろうか(多分)

さて、私は今日これを回避することができた。そうOptionalで!

PlayFrameworkを使ってのOptionalなので、Java8ではなくJava7でScalaのライブラリを利用して使用している。これは本当にすばらしいものだと思う。

でも、あんまり理解していないので、詳しくはちゃんと勉強して公開することにして、今回はちょっとだけ。

Playframeworkの場合は下記でラッピングするといいと思う。(と、書籍に書いてあっただけだけど)

package utils;

import play.libs.F;
import scala.*;
import java.util.List;

/**
 * Option用ユーティリティクラス
 */
public class OptionUtil {

    public static <A> F.Option<A> apply(A value) {
        if(value != null) {
            return F.Option.Some(value);
        } else {
            return F.Option.None();
        }
    }

    public static <A> F.Option<List<A>> apply(List<A> value) {
        if(value != null && value.size() != 0) {
            return F.Option.Some(value);
        } else {
            return F.Option.None();
        }
    }

    public static <String> F.Option<String> applyWithString(String value) {
        if(value != null && !value.equals("")) {
            return F.Option.Some(value);
        } else {
            return F.Option.None();
        }
    }

    public static <T> F.None<T> none() {
        return new F.None<T>();
    }

    public static <T> Option<T> asScala(F.Option<T> value) {
        if(value.isDefined()) {
            return Option$.MODULE$.apply(value.get());
        } else {
            return Option$.MODULE$.empty();
        }
    }

}

このクラスはこう使う

     // default のobjectを作る
    private static MyClass defaultInstance() {
        MyClass myObject = new MyClass();
        return myObject;
    }

    public static MyClass getObject() {
        // テーブルから一行データを取り出す。しかしデータが入っているかわからない。
        // もし入っている場合はObject、入っていない場合はnullになる。
        MyClass myObject = MyClass.FINDER.setMaxRows(1).findUnique();
        Option<MyClass> myClassOpt = OptionUtil.apply(myObject); // ↑のOptionUtilへ渡す。nullだったらNone、でなければSomeが返る。
        MyClass safeMyClass = myClassOpt.getOrElse(defaultInstance()); // getOrElseで分岐できる。すばらしい!
        return safeMyClass;
    }

オブジェクトであればなんでもいい。StringでもIntegerでも、自作クラスでもいい。

本日ちょうど、運用中のアプリケーションでぬるぽが発生した。しかし、私は上記クラスを思い出し、それで実装した。問題は解決し、コード上でも安全であることがわかるように組めた。

ありがとうOptional。今後はこれを絶対使って生きていこうと思う。

と、酔っ払っているからなんか文章へんかもしれないけど助かった。本当にありがとう(´;ω;`)ブワッ