10年の長きに渡り Java の可変長引数を過信していた話

f:id:Naotsugu:20170622220119p:plain


可変長引数のループで ヌルポ発生

先日とあるプロジェクトで、可変長引数を for - each している箇所でヌルポになっていた。

実際にはずっと複雑だが、簡単に書くと以下のような for ループでのヌルポ。

public void method(String... args) {
    for (String string : args) {    // java.lang.NullPointerException
        // ...
    }
}

この10年 可変長引数が null を受け取るなんて。

可能性すら考えるまでもなく問題なしと思い込んでいた。

普通の呼び出し

普通に呼び出すと、

method();

method("hello");

method("hello", "world");

それぞれ長さが 0, 1, 2 の文字列配列が渡る。

変数でも、null の変数だと、

String str = "hello";
method(str);

str = null;
method(str);

長さ1の配列と、長さ0の配列になりヌルポにはならない。

なんだ!? これ

何をしたかったのか謎だが、あえてリテラルnull 渡してた。

method(null);

java.lang.NullPointerException になる。

まぁ、そりゃそうか。

念のため

以下の可変長引数は、

public void method(String... args) { }

コンパイル後は以下と同じになる。

public void method(String[] args) { }


以下のような呼び出しは、

method("hello");

コンパイル後は以下と同じになる。

method(new String[] { "hello" });

とすると先の例は、コンパイル後のコードは以下になる。

String str = null;
method(new String[] { str });

直接 null 渡せば、ヌルポ。

method(null);

どうしても null を渡したい場合

以下のようにキャストすればヌルポにはならない。

method((String) null);

配列としてキャストすると、

method((String[]) null);

これはヌルポ。

まとめ

でも普通に考えて、null チェックはしないかな。