Infinito Nirone 7

白羽の矢を刺すスタイル

potatotips #17 行ってきた

このところ抽選の倍率が高くてなかなか参加できていなかったのですが、ようやく機会を得たので参加してきました。

今回は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 を入れようと思えば入れられるし、実際混入する可能性はいくらでもあるということになります。

ただ、Javadocnull について徒然なるままにドキュメントを書くよりは、圧倒的に万人に分かりやすく null について表明することができる点においては、どんどん使って行ったほうがいいな、と思っています。

最後、発想を転換して、無いことをもオブジェクトとして取り扱ってしまおう、というのが NullObject パターンです。 実装の中身さえ空なら呼び出してもさしたる影響はないはずですから、そういう空の実装をもったオブジェクトを作って、null の代わりに返してあげれば、使う側は null かどうかを気にする必要がなくなります。

そういうわけで、メソッドの返り値にnullを使わないほうがいいパターンというのも勿論あります。特に、コレクションを扱う場合には、nullよりも空のコレクションが好まれます。 あるいは、異常を示すためのnullではなく、ちゃんと例外としてきちんと設計することが好まれるものもあります。 この辺りはケースバイケースなことも多いですが、nullに存在が無いということの他に意味を持つような実装をしようとしているなら、nullではない何かを考慮してもよいのかもしれませんね。

ともあれ、このあたりの話題は EffectiveJava に詳細が書かれていますので、是非読んでみてください。

と言う王道パターンがあるわけなんですが、Android ではいくつか苦しいポイントがあって、特に互換ライブラリには非常にお世話になる一方、実装面で言うと、古いバージョンでは存在しないクラスを取り扱うための苦労が 垣間見えます。 その中でも、API レベルによって処理を分けるためのデリゲートクラスの実装はなかなかに趣があり、古いバージョンでは取り敢えず何もしたくないということで、 メソッドの中身が無かったり、return null; とか書いてあったりします。そこは例外じゃないんだ…という気分ですが、 普通に自分の書いたコードに null が混入してきます。このあたりは、Support Library の実装を見ながら書かないとハマるポイントになるなあと思っています。