参照型の配列とNullPointerException

参照型の配列

参照型の配列を作成することもできます。

以下のExample06は参照型の配列の例です。

package chap09;

public class Example06 {

	public static void main(String[] args) {
		NewEngineer2[] se = new NewEngineer2[3];
		se[0] = new NewEngineer2();
		se[1] = new NewEngineer2();
		se[2] = new NewEngineer2();
		se[0].id = 1;
		se[0].name = "tabuchi";
		se[1].id = 2;
		se[1].name = "shinohara";
		se[2].id = 3;
		se[2].name = "kokubun";
		for (NewEngineer2 newEngineer2 : se) {
			newEngineer2.show();
		}
	}
}
実行結果の予想:


ただし、その作られ方には違いがあります。

以下の下図のようにプリミティブ型は配列に直接値が格納されるのに対して、オブジェクト型の場合には配列からまた参照をたどった先にインスタンスがあります。

プリミティブ型の配列とオブジェクト型の配列の違い

NullPointerException

このとき、新人エンジニアのみなさんが起こしがちなミスとして、配列は作ったものの、インスタンスを作り忘れるというものがあります。

例えば、以下のExample07はインスタンスを作り忘れてNullPointerExceptionが発生する例です。

package chap09;

public class Example07 {

	public static void main(String[] args) {
		NewEngineer2[] se = new NewEngineer2[3];
		se[0].id = 1;
		se[0].name = "tabuchi";
		se[1].id = 2;
		se[1].name = "shinohara";
		se[2].id = 3;
		se[2].name = "kokubun";
		for (NewEngineer2 newEngineer2 : se) {
			newEngineer2.show();
		}
	}
}

<実行結果>

xception in thread "main" java.lang.NullPointerException: Cannot assign field "id" because "se[0]" is null
at chap09.Example07.main(Example07.java:7)

7行目で「NullPointerException」が発生しました。Pointer(参照)がNull(空)であるというException(例外)です。

※ポインタとはC言語等で使われる参照(のようなもの)です。用語が先祖返りしているのが興味深いですね。

se[0]には何も入っていないのに、その参照を使おうとしたことが原因です。先のNullPointerExceptionが起きなかった場合と図解で比較してみると下図のようになります。

NullPointerExceptionが起きる場合、起きない場合
NullPointerExceptionが起きる場合、起きない場合

オブジェクト型の配列の場合は、最初は参照に何も入っていないnullという状態なのです。例えるなら、リモコンはあるけれども肝心のTVやエアコンがない状態と言ったら良いでしょうか?参照はあってもインスタンスがないとNullPointerExceptionが起きるのです。

おそらく、これから新人エンジニアの皆さんが学習を進めていくうえで、一番多く遭遇するのがこのNullPointerExceptionです。

しかも、このNullPointerExceptionは非検査例外といってプログラマの責任で必ず対処しておかなければならない例外なのです。よって、IDEもチェックしてくれません。
例外のところで詳述します。

nullは、特別な値で参照型の変数に代入することができます。

package chap09;

public class Example08 {

    public static void main(String[] args) {
        NewEngineer2 se = null;
        System.out.println(se);
    }
}

<実行結果>

null

参照先が未設定(null)で実体がない参照型を使おうとしたときに発生するのがNullPointerExceptionです。

以下のサンプルコードを見て下さい。

package chap09;

public class Example09 {

    public static void main(String[] args) {
        String str1 = null;
        System.out.println(str1.length());
    }
}

<実行結果>

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "str1" is null
at chap09.Example09.main(Example09.java:7)

nullは文字列の"null"とも、""(空文字)とも数値の0とも違います。参照型なのに参照先が未設定な場合に、つまり実体がまだ無い参照型が持つ特別な値なのです。

以下のExample10を見て下さい。

package chap09;

public class Example10 {

    public static void main(String[] args) {
        String str1 = null;
        System.out.println(str1 == null);
        System.out.println(str1 == "null");
        System.out.println(str1 == "");
    }
}
実行結果の予想:


ちなみに、Javaにはガーベージコレクション(Garbage collection:ゴミ集め)という機構があり、どこからも参照されなくなったインスタンスはプログラマが何もしなくても自動的にメモリから消去されます。new演算子でメモリが確保され、ガーベージコレクションが自動でメモリを解放してくれるのです。このおかげで、メモリの確保と開放という作業が不要になりました。

この仕組みがない言語(C、C++等)では、プログラマが都度必要なメモリをOSから借り、不要になったら解放しなければなりません。メモリを借りっぱなしにしておくと、メモリリーク (memory leak:メモリ漏れ) という下手をすればシステムを破壊しかねない深刻なエラーが起こります。

今では当たり前の機能ですが、Javaが登場した当時はガーベージコレクションの仕組みを備えていたことも画期的なことでした。


セイ・コンサルティング・グループの新人エンジニア研修のメニューへのリンク

投稿者プロフィール

山崎講師
山崎講師代表取締役
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。