このところ抽選の倍率が高くてなかなか参加できていなかったのですが、ようやく機会を得たので参加してきました。
今回はnull
についての王道パターンの対応策と、Android における深い闇について話しました。
null
はちゃんと取り扱わないとすぐNullPointerException
で落ちます。ちゃんと取り扱っていても、予期しない理由でNullPointerException
で落ちることもありますが、
それはかなりレアケースなので、今回の話のスコープとしては取り扱いませんでした。
最も簡単かつお手軽な手法は、なんといっても Null Check の if 文です。null
だったら何もしないとか、null
だったら異常なので例外を投げるとか。
基本中の基本といったところですが、null
とはそもそも何だったのかということを忘れていると、あちこちで Null Check をし始めてしまい、結果同じものに 3 回も 4 回も Null Check してしまって無駄が多くなる、
みたいなことになり得ます。
null
とは値が存在しない、無、ということなので、本当に何も無い時だけnull
を返してあげるのが理想です。そのことについて Null Check をしてあげる、と言うのは是非すべきだと思います。
さて、Android には SupportAnnotation と言って、Lint のサポートを活用するべく作られた、値が Null になり得るかどうかを示すためのアノテーションがあります。
@NonNull
アノテーションが付いている変数あるいはメソッドの戻り値は、必ず何かしらのオブジェクトが存在することが期待できることを意味します。
@Nullable
はその逆で、null
が入る可能性があることを期待していることになります。
ここで「期待している」と言っているのは、あくまで Lint が警告を出すだけのためのアノテーションであって、コンパイルエラーにしてくれるとか、何かいい感じにnull
が取り扱えるようになる魔法をかけてくれるとか、
そういうことではないということです。つまり、Lint が警告を出さなくても null
を入れようと思えば入れられるし、実際混入する可能性はいくらでもあるということになります。
ただ、Javadoc に null
について徒然なるままにドキュメントを書くよりは、圧倒的に万人に分かりやすく null
について表明することができる点においては、どんどん使って行ったほうがいいな、と思っています。
最後、発想を転換して、無いことをもオブジェクトとして取り扱ってしまおう、というのが NullObject パターンです。
実装の中身さえ空なら呼び出してもさしたる影響はないはずですから、そういう空の実装をもったオブジェクトを作って、null
の代わりに返してあげれば、使う側は null
かどうかを気にする必要がなくなります。
そういうわけで、メソッドの返り値にnull
を使わないほうがいいパターンというのも勿論あります。特に、コレクションを扱う場合には、null
よりも空のコレクションが好まれます。
あるいは、異常を示すためのnull
ではなく、ちゃんと例外としてきちんと設計することが好まれるものもあります。
この辺りはケースバイケースなことも多いですが、null
に存在が無いということの他に意味を持つような実装をしようとしているなら、null
ではない何かを考慮してもよいのかもしれませんね。
ともあれ、このあたりの話題は EffectiveJava に詳細が書かれていますので、是非読んでみてください。
と言う王道パターンがあるわけなんですが、Android ではいくつか苦しいポイントがあって、特に互換ライブラリには非常にお世話になる一方、実装面で言うと、古いバージョンでは存在しないクラスを取り扱うための苦労が
垣間見えます。
その中でも、API レベルによって処理を分けるためのデリゲートクラスの実装はなかなかに趣があり、古いバージョンでは取り敢えず何もしたくないということで、
メソッドの中身が無かったり、return null;
とか書いてあったりします。そこは例外じゃないんだ…という気分ですが、
普通に自分の書いたコードに null
が混入してきます。このあたりは、Support Library の実装を見ながら書かないとハマるポイントになるなあと思っています。