こんにちは。今回はJavaのwhile文についてです。このブログでは以前に、以下の記事でwhile文の基本的な記述方法について書きました。
while文の式(キー)にはプリミティブ型char, byte, short, intを使うことができます。上記の記事ではwhile文のキーにint型を使いました。今回はwhile文のキーにint型のラッパークラスであるInteger型を使ってみました。
この記事の前半ではInteger型について、簡単な説明を書きました。後半ではwhile文の式にInteger型を使った時の動作について書きました。
Integer型の簡単な説明
Javaの変数には大きな分類としてプリミティブ型と参照型があります。
プリミティブ型変数は値を直接保持します。プリミティブ型のひとつとしてint型があります。int型変数は整数値を格納できる型です。(値の範囲については省略します。)
以下はint型変数に値を格納して出力するだけの簡単なサンプルです。
int型の使用例
int my_value = 1;
System.out.println(my_value);
System.out.println("-------------------");
my_value = 2;
System.out.println(my_value);
結果
1
-------------------
2
上記サンプルのように、int型変数は値を代入できます。
Javaにはプリミティブ型に対してラッパークラスが用意されています。ラッパークラスは参照型です。int型のラッパークラスはInteger型です。
以下は簡単な動作確認です。
ソース
Integer my_value = Integer.valueOf(1); // (1)
System.out.println(my_value.getClass()); // (2)
System.out.println(my_value.intValue()); // (3)
System.out.println(my_value); // (4)
System.out.println("------------------------------");
my_value = 2; // (5)
System.out.println(my_value); // (6)
System.out.println("------------------------------");
my_value = null; // (7)
System.out.println(my_value); // (8)
結果
class java.lang.Integer
1
1
------------------------------
2
------------------------------
null
(1)のInteger.valueOf()メソッドは指定されたint値を表すIntegerインスタンスを返します。このメソッドはキャッシュを利用します。そのため、newを使ってコンストラクタを呼び出すより、このメソッドを使った方が良いです。
(2)ではgetClass()メソッドでクラス名を取得しています。実行結果の通り、変数my_valueに格納されているのはInteger型のインスタンスです。このインスタンスが値を保持しています。
(3)のintValue()メソッドはIntegerの値をintとして返します。
(4)ではprintln()メソッドの実引数に直接my_valueを指定しています。この場合、Integer.toString()メソッドが実行されます。このメソッドはIntegerの値を文字列として返します。
(5)のように代入式の右辺に数値を記述できます。コンパイラ側でラッパークラスに自動変換されます。ただし、Java1.4以前ではエラーになるようです。(6)の出力結果を見ると、(5)で値2を持つInteger型のインスタンスが生成されたことがわかります。
(7)では変数my_valueにnullを格納しています。Integer型は参照型なので変数にnullを格納できます。(8)の出力結果を見ると、nullという文字列が出力されています。println()メソッドは引数にnullを指定すると「null」という文字列を出力します。
while文でInteger型を使ったときの動作
while文でInteger型が使えることを以下のサンプルを作って確認しました。
ソース
public class Test001 {
public static void main(String[] args) {
Integer integer = Integer.valueOf(1);
System.out.println(getMsg(integer));
integer = Integer.valueOf(2);
System.out.println(getMsg(integer));
}
private static String getMsg(Integer integer) {
String msg = null;
switch (integer) {
case 1:
msg = "CASE 1の処理です。";
break;
default:
msg = "デフォルトの処理です。";
break;
}
return msg;
}
}
結果
CASE 1の処理です。
デフォルトの処理です。
上記サンプルのgetMsg()メソッドではswitch文のキーに仮引数のInteger型変数integerを指定しています。
main()メソッドではgetMsg()メソッドを呼び出しています。最初はIntegerの値を1にして、引数に指定しています。次にIntegerの値を2にして、引数に指定指定しています。実行結果を見ると、問題なく動作しているのが確認できました。
while文でNullPointerExceptionが発生する場合
Integer型変数にはnullを格納できます。そのため、getMsg()メソッドのswitch文では、キーがnullの可能性があります。その場合の動作を以下のサンプルを作って確認しました。
ソース
package test_20220816_switch_integer.sample;
public class Test002 {
public static void main(String[] args) {
Integer integer = Integer.valueOf(1);
System.out.println(getMsg(integer));
integer = Integer.valueOf(2);
System.out.println(getMsg(integer));
integer = null; // (1)
System.out.println(getMsg(integer)); // (2)
}
private static String getMsg(Integer integer) {
String msg = null;
switch (integer) {
case 1:
msg = "CASE 1の処理です。";
break;
default:
msg = "デフォルトの処理です。";
break;
}
return msg;
}
}
結果
CASE 1の処理です。
デフォルトの処理です。
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "integer" is null
at test_20220816_switch_integer.sample.Test002.getMsg(Test002.java:19)
at test_20220816_switch_integer.sample.Test002.main(Test002.java:13)
(1)でInteger型変数integerにnullを格納し、その変数を(2)でgetMsg()メソッドの引数に指定しています。
結果からわかるように、switch文のキーがnullの場合、NullPointerExceptionが発生します。
エラーが発生しないようにするためには、例えば、以下のようにswitch文の前にnullチェックをする方法があります。
ソース
package test_20220816_switch_integer.sample;
public class Test003 {
public static void main(String[] args) {
Integer integer = Integer.valueOf(1);
System.out.println(getMsg(integer));
integer = Integer.valueOf(2);
System.out.println(getMsg(integer));
integer = null; // (1)
System.out.println(getMsg(integer)); // (2)
}
private static String getMsg(Integer integer) {
// 引数がnullの場合、nullをリターン
if (integer == null) {
return null;
}
String msg = null;
switch (integer) {
case 1:
msg = "CASE 1の処理です。";
break;
default:
msg = "デフォルトの処理です。";
break;
}
return msg;
}
}
結果
CASE 1の処理です。
デフォルトの処理です。
null
上記のgetMsg()メソッドでは最初に引数がnullであるかどうかをif文でチェックしています。引数がnullの場合、nullをリターンしています。return文が実行されるので、メソッドの処理はその行で終了です。
実行結果を見ると、例外が発生していないことがわかります。
上記はメソッドの引数にしている変数にnullが格納されていた場合ですが、そのほかの可能性として、Integer型配列の要素を使っている場合を思いつきました。
以下のサンプルでは、配列をfor文を使って、switch文のキーに配列の要素を指定しています。
ソース
package test_20220816_switch_integer.sample;
public class Test004 {
public static void main(String[] args) {
Integer[] integers = {
Integer.valueOf(1), Integer.valueOf(2),
Integer.valueOf(3), null };
for (int i = 0; i < integers.length; i++) {
System.out.println("i:" + i);
System.out.println(getMsg(integers[i]));
}
}
private static String getMsg(Integer integer) {
String msg = null;
switch (integer) {
case 1:
msg = "CASE 1の処理です。";
break;
case 2:
msg = "CASE 2の処理です。";
break;
default:
msg = "デフォルトの処理です。";
break;
}
return msg;
}
}
結果
i:0
CASE 1の処理です。
i:1
CASE 2の処理です。
i:2
デフォルトの処理です。
i:3
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because "integer" is null
at test_20220816_switch_integer.sample.Test004.getMsg(Test004.java:19)
at test_20220816_switch_integer.sample.Test004.main(Test004.java:12)
上記サンプルでは最初にinteger型配列integersを定義しています。想定としては、例えば画面側から年齢の一覧などを受け取ってintegersに配列として受け取っているという状況です。上記では配列の要素のうち、最初の3つはインスタンスです。4つ目がnullです。画面側で未入力のため、nullを受け取ったという想定です。
for文ではgetMsg()メソッドを呼び出しています。引数にintegersのi番目の要素を指定しています。
上記サンプルのgetMsg()メソッドには引数のnullチェックは実装してません。実行結果を見ると、iの値が3のときNullPointerExceptionが発生しました。
このように、integer型配列の要素にはnullが設定できるため、注意が必要です。
以上、参考になれば幸いです。