ちぎっては投げるブログ

Programming, Android, RaspberryPi, Digital Devices, Kinkuma Hamster...

毎回 object != null を書かないためには(Java)

StackOverflowから。

f:id:mczh:20160228180858j:plain Photo by Photo by Nafinia Putra | Unsplash / CC BY 0

stackoverflow.com

Javaで、nullチェックとして毎回object != nullと書くと見苦しい、代わりの良い方法はない?というスレッド。 本日のTILとして、これをざっくり眺めたまとめ。英語力低いのであってるか怪しい。

単純に毎回nullチェックする派

if (someobject != null) {
    someobject.doCalc();
}

関数の頭でチェックして、nullなら例外投げとけば?派

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

ふつうだ。

派生として、nullならreturnしちゃえば?もあると思う。C++だと例外が使いにくい(というより、C言語のコードと混ざった環境だと実質使えないと聞く)ので、returnをよく見る。

メソッド自体がNullPointerException投げるようにしちゃえば?派

nullもありえると許容して、呼び出す元でtry-catchしてもらえばいいんじゃない?という考え。

requireNonNull使う派

例外を投げる。

【Java】サヨナラNullチェック!requireNonNullが便利すぎた! | mokabuu.com

Google Guavaライブラリにある、checkNotNullも似たようなことが出来るらしい。

public void doSomething(String message) {
    this.message = checkNotNull(message, "message must not be null");
}

これで、NullPointerExceptionが投げられる。

メソッド内でパラメータの値チェックを行う - Qiita

アノテーション使えば?派

@NotNullという注釈を使うことで、関数がnullを返さないことや、引数がnullでないことをコンパイラレベルで確認してコンパイルエラーに出来るらしい。

JSR-305: ソフトウェア欠陥検出用アノテーション

IntelliJ IDEAやEclipse、Netbeansでも利用できる。IDEの設定が必要な場合もある。

関数自体がnullを返すことを禁止するには、

@NotNull public static String helloWorld() {
    return "Hello World";
}

引数なら、

void someMethod(@NotNull someParameter) { }

逆に、nullを返すこともあるよ!と明示するには、@Nullableとする。

便利だけど、今のところ標準ではなくJSR-305のライブラリを追加しないといけない(たぶん)というのがイケてない。

このJSR-305は、Java 7の一部として提供される予定であるが、言語を変更する必要はなく、エキスパート グループは Java 5以降のサポートを目指している。エキスパート グループのメンバーには、Sun、Google、JetBrainsおよびDoug Leaが含まれている。

Null Object作れば?派

Null Object パターン。

thinkit.co.jp

定数との比較系なら、逆にすればヌルポしないよ

こうじゃなくて、

if ( foo.equals("bar") ) {
 // ...
}

こう。

if ( "bar".equals(foo) ) {
 // ...
}

これは結構やる。ヨーダ記法に通ずるものがある、というか、ヨーダ記法か?

最初から初期化しとけ派

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}

// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

メンバ変数に関してはむしろコンストラクタなどで初期化しとけば?って思ったけど、Javaだとどっちが一般的だろう?C++だとコンストラクタで初期化する。 ちなみに、メンバ変数以外のnullチェックの場合も当然あるので、これだけだと足りてないのは言うまでもない。

まとめ

英語だと議論が読めない・・・。NullObjectパターンか、アノテーション使っておけ、っていうのが多いように見えた。そこまでするレベルじゃなければ、頭でnullチェックして例外投げる、で良い気がする。

ところで、「本日のTIL」って「頭痛で頭が痛い」的な感じになるね。