家の中でのこだわりスペースはどこですか?

Java配列で、要素にnullが指定されているのに、NullPointerExceptionになるケースとならないケースの差がわかりません

インプレス社 Java SE Silver 8の問題集の第四章 項5と項6で、一見相反するかのような正答があり混乱しています。

その箇所を抜き出すと次のような感じです。

項5 次のプログラムをコンパイル、実行したときの結果として、正しいものを選びなさい(一つ選択)
public class Item {
String name;
int price = 100;
}

public class Main{
public static void main(String[] arigs){
int total = 0;
for (int i = 0; i < items.length; i++){
total += items[i].price;
}
System.out.println(total);
}
}
A.0が表示される。
B.200が表示される。
C.300が表示される。
D.コンパイルエラーが発生する
E.実行時に例外がスローされる


項6 次のプログラムをコンパイル、実行したときの結果として、正しいものを選びなさい(一つ選択)
public class Main{
public static void main(String[] args){
String[] array = {"A","B","C","D"};
array[0] = null;
for (String str : array){
System.out.print(str);
}
}
}

A.「ABCD」と表示される。
B.「BCD」と表示される。
C.「nullBCD」と表示される。
D.「null」と表示される。
E.コンパイルエラーが発生する。
F.実行時にエラーがスローされる。

尚、上記の項5の正解はEで、項6の正解はCとありました。
それぞれの理由を記載すると、
項5:
Item[] items = new Item[3];の時点で配列インスタンスは生成したが、Itemのインスタンスを生成したわけではないので、全てnullが入っている。
配列の中での各要素の参照先が存在しないため、NullPointerExcetptionが発生する。

項6:
配列インスタンスの4つの要素は「null」と「B、C、DのStringインスタンスの参照」です。そのため、コンソールには「nullBCD」と表示されます。


とのことで、nullに対する扱いが理解できません。
類推するに、項5ではnullを明示的に入れておらず、項6ではnullを明示的に入れているので、配列インスタンスを生成しただけで、中身のオブジェクトは入れていないという状態での、要素の中の状態は参照先が無いと思っているのですが、これは明示的にnullを指定するケースと異なると言うことなのでしょうか(私の中では要素の中で参照先がない状態と、明示的にnullを要素指定した場合は同一だと思っているのですが、この認識が誤っているのでしょうか)。

もしくはString型だけ特別扱いで、nullが指定されていればnullと表示してくれるのでしょうか。

質問者からの補足コメント

  • すみません、肝心の問題文に誤りがありました。

    項5は

    public class Item {
    String name;
    int price = 100;
    }

    public class Main{
    public static void main(String[] arigs){
    Item[] items = new Item[3];
    int total = 0;
    for (int i = 0; i < items.length; i++){
    total += items[i].price;
    }
    System.out.println(total);
    }
    }

    となります。大変失礼しました。

      補足日時:2019/05/04 06:23

A 回答 (6件)

「そもそもNullPointerExceptionってそんなものだから。

」としか言いようがありません。

まずそもそもNullPointerExceptionはnull pointer exceptionではありません。
null pointer's sub field or method reference exceptionです。
つまりですね、null値を参照しただけでは発生しません。
null値のフィールドやメソッドを参照した時に初めて発生します。
#ネーミングセンスどうよとは思いますが正確を期すと名前が長すぎて例外処理を書く度にFワードを吐く事になるので致し方ないです。

では各項に当てはめて行きます。

項4の場合は下に示した行でNullPointerExceptionが発生します。
total += items[i].price;
items[i]がnull値でnull値のpriceを参照しようとしてNullPointerExceptionとなります。

一方項5の場合は、System.out.pintの中身と関係があります。
ざっくりといろいろ省略して以下の様な感じです。
#但しシステムのPrint関数をSysPrintとして表記します。
void print(Object value){
if(value==null){
SysPrint(”null”);
}else{
SysPrint(value.ToString());
}
}
null値を参照しますが、null値のフィールドやメソッドは参照していません。
ですから例外は発生しないしません。
    • good
    • 1
この回答へのお礼

なるほど! 
分かりやすい説明ありがとうございました。
nullが来てもヌルポで落ちないように特別扱いしているんですね。
これで理解できました。

お礼日時:2019/05/12 18:17

さて, どういう動作をするか想像したところで, 実際に動かしてみましょう.



どうなりましたか?
    • good
    • 0
この回答へのお礼

ありがとうございます。
System.out.printlnはnullでどうして動くのかなと不思議に思っていました。
No.4の方の通りでしたね。

お礼日時:2019/05/26 00:05

Sytem.out.print は null を受けとると "null"と表示する「仕様」になっている。


それだけですよ。
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
こちらも理解しました。

お礼日時:2019/05/12 18:18

そもそもプリミティブ型だと null が存在しない... けど, 今回とは関係ない話.



項5 と項6 のプログラムを, それぞれ
5'
public class Item {
String name;
int price = 100;
}

public class Main{
public static void main(String[] arigs){
Item[] items = new Item[3];
for (int i = 0; i < items.length; i++){
System.out.println(items[i]);
}
}
}

6'
public class Main{
public static void main(String[] args){
String[] array = {"A","B","C","D"};
array[0] = null;
int len = 0;
for (String str : array){
len += str.length();
}
System.out.println(len);
}
}

としたらどうなるかわかりますか?
    • good
    • 0
この回答へのお礼

>プリミティブ型だと null が存在しない
なるほど・・・不勉強でした。一つ勉強になりました。ありがとうございます。

例題もありがとうございます。
これはこれまでの文脈からすると、(私の頭の中ではヌルポで落ちると思っていましたが)
No.5の方は、
System.out.println(items[i]);
の部分で三回
null
null
null
と出力されるとおもいます。
No.6の方は、事前に配列の中身も入っているので、特にエラーになることもなく
str.length()の4が拡張for文の中で4回足しこまれて
最後の
System.out.println(len);
で16が出力されるように思います。合っていますか?

お礼日時:2019/05/12 18:13

#1 に書いておいたんだけどね... あ, println じゃなくて print だった. 本質は変わらないけど.

    • good
    • 0
この回答へのお礼

回答有り難うございます。
#1の回答ですが、
>「null が参照するインスタンス」にアクセスしてるけど, 項6 では「null が参照するインスタンス」にはアクセスしなくていいよね.
これはインスタンスかプリミティブの違いか、と言うことなのでしょうか。

お礼日時:2019/05/06 00:32

項5 って, これだと「コンパイルエラーが発生する」が正しいのでは? 下には


Item[] items = new Item[3];の時点で
って書いてあるけど, こんな文はどこにもないですよ.

さておき, 項5 では「null が参照するインスタンス」にアクセスしてるけど, 項6 では「null が参照するインスタンス」にはアクセスしなくていいよね.

まあ System.out.println が null を特別扱いしてるのも事実.
    • good
    • 0
この回答へのお礼

すみません、肝心の問題文に誤りがありました。

項5は

public class Item {
String name;
int price = 100;
}

public class Main{
public static void main(String[] arigs){
Item[] items = new Item[3];
int total = 0;
for (int i = 0; i < items.length; i++){
total += items[i].price;
}
System.out.println(total);
}
}

となります。大変失礼しました。

お礼日時:2019/05/04 06:22

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


おすすめ情報

このQ&Aを見た人がよく見るQ&A