前書き
本記事は5分程度で読めます。
Javaの基本を習得している方向けの内容です。
Java SE11 silver勉強中に、
「NULLの取り扱い難しいなー」って思ったことありませんか?
私は、毎日NULLと格闘してました。
今ではNULLもあまり怖く無くなってきました。
そんなあなたに、NULLのことが好きになる?!NULLの攻略方法をご紹介します✨
NULLとは
そもそもNULL
ってなんだっけ?
nullは、変数の値に何も定義されていない(何も入っていない)状態を表す特殊は値です。
NULLっていうのは何も参照されていない状態なんですね!
ちなみにNULLを許容できるのは 参照型 のみです。
↓簡単な見分け方
型の種類 | 見分け方 | 例 |
---|---|---|
プリミティブ型 | 小文字で始まる | int, double, byte |
参照型 | 大文字で始まる | Sample, Object, Integer, Double |
問題の中で解説
では、どんなところが難しいのか、問題を見ながら考えましょう
(問題はJava SE11 Silver黒本を参考にしています)
解答はまとめて最後に記載してありますので、ペンとメモを用意して何点正解できるか試してみましょう!
全部で5問用意しました
問題
問題1
次のプログラムを実行した結果として正しいものを選びなさい
String str = null;
System.out.println(str);
A. nullと表示される
B. コンパイルエラーが発生する
C. 例外がスローされる
問題2
次のプログラムを実行した結果として正しいものを選びなさい
public class Question02 {
public String str;
public void Question02(){
this.str = "hello";
}
public static void main(String[] args) {
Question02 question = new Question02();
System.out.println(question.str);
}
}
A. nullと表示される
B. helloと表示される
C. コンパイルエラーが発生する
D. 例外がスローされる
問題3
次のプログラムを実行した結果として正しいものを選びなさい
public class Question03 {
public static void main(String[] args) {
String str = null;
str += "null";
System.out.println(str);
}
}
A. nullと表示される
B. nullnullと表示される
C. 何も表示されない
D. コンパイルエラーが発生する
問題4
次のプログラムを実行した結果として正しいものを選びなさい
public class Question04 {
public static void main(String[] args) {
String[] str = new String[2];
int i = 0;
for(String s: str) {
str[i].concat("e" + i);
i++;
}
for(i = 0; i < str.length; i++) {
System.out.println(str[i]);
}
}
}
A. e0
e1
B. null e0
null e1
C. null
null
D. 実行時に例外がスローされる
問題5
次のプログラムを実行した結果として正しいものを選びなさい
public class Question05 {
public static void main(String[] args) {
String str;
Object obj = null;
if(str == obj) {
System.out.println("A");
} else {
System.out.println("B");
}
}
}
A. Aと表示される
B. Bと表示される
C.コンパイルエラーが発生する
D. 例外がスローされる
解答
問題 | 解答 |
---|---|
1 | A |
2 | A |
3 | B |
4 | D |
5 | C |
解説
問題1
これはnullをSystem.out.println
メソッドで出力できるか?という問題です。
参照を持たないことを表すnullは、"null"という文字列に置き換えられて文字列として出力されます。
問題2
フィールドの初期値に関する問題です。
フィールドの初期値は以下の様になっています
型 | 初期値 |
---|---|
boolean型 | false |
文字型(char) | '¥u0000' |
整数型(int) | 0 |
浮動小数点型(double,float) | 0.0 |
参照型(String型, 配列) | null |
public void Question02(){}
というのは、コンストラクタの様に見えますが、戻り値(void)が記載されているので、これは普通のメソッドとして判定されます。
通常のメソッドがクラス名と同じではいけないというルールはないのでコンパイルエラーにはなりません。
Question02型の変数questionの持っているフィールドstrは初期値null
のまま上書きされていないので、出力するとそのままnull
と出力されます。
問題3
演算子による文字列の連結に関する問題です。
設問コードのように、参照を持たないString型変数に対し、演算子を使って文字列同士を連結することが出来ます。
この時、参照を持たないnullは"null"という文字列に置き換えられて、文字列として連結します。
問題4
配列に関する問題です。
オブジェクト型の配列インスタンスを生成しても、配列で扱いたい要素のインスタンスが生成されるわけではありません。
あくまで配列のインスタンスが生成されるだけで、要素の中身は空、つまりnullです。
拡張for文で配列の要素を取り出していますが、変数sにはnullが入っています。
そのため次の行でconcatメソッドを読んだタイミングで NullPointerException がスローされます。
問題5
ローカル変数の問題です。
問題2ではフィールドが初期化されてnullとなっていましたが、
メソッドの中にあるローカル変数は明示的に初期化をしないと使用できません。
if文のところで、初期化していないローカル変数を使用しようとしたというコンパイルエラーが発生します。
補足:コンパイルエラーと例外の違い
コンパイルエラーは構文に間違いがあり、コンパイラによって検出可能である場合にコンパイルエラーとなります。
例外は、構文に誤りがなく、コンパイラによって検出されない場合に例外となります。
NullPointerExceptionはその代表的な例外の一つで、非検査例外です。
見分けるポイントは、構文に誤りがないかどうか?というところです。
例えば、
Sample sample = null;
sample.toString();
これはコンパイラにとって、構文に誤りがないのでコンパイルエラーにはなりません。
逆にこれはどうでしょう?
public static void main(String[] args){
String str;
System.out.println(str);
}
メソッドの中でString型の変数strを宣言して初期化せずに次の行で使用しています。
これはコンパイラでチェックできるので、コンパイルエラーになります。
まとめ
どうでしたか?皆さんは何問解けましたか?🔥
改めて解いてみると意外と悩んだりするものですよね。。。
いろんなパターンごとに挙動が異なるので、この時はこう、あの時はこう、
みたいにパターンごとに覚えちゃったほうが早いと思います。
Java Silverでは結構nullについての問題が出題されますので、
これから受けてみようと考えているかたは、是非この記事を参考にnullについて学びましょう!