今回はJavaを使う時に、初心者がミスを犯しやすい==の等号2つの比較についてお話しします。
基本的に文字列の比較で==を使ってはいけないことを理解しておけば十分ですが、間違って使ってしまった場合も普通に正しい比較が出来てしまうケースもあります。
これはなぜなのかについてもお話しします。
Javaの==による数値比較の考え方
まず、Javaにおいて数値の比較は普通に==を使って問題ありません。
以下のようにメソッドを定義して呼び出すことで、実行してみます。
//数値同士を比較してみる
public void CompareInt2Int() {
int int1 = 8;
int int2 = 8;
//equalsで比較してみる(等号の動作が正しければ「等しい」と表示される)
if(int1 == int2) {
System.out.println("等しい");
} else {
System.out.println("等しくない");
}
}
この判定結果を見てみましょう。
無事に2つの変数に入れた数値が等しいことが確認できました。
intなどのように同じ型の数値同士の比較であれば==で比較して特に問題ありません。
C言語と同じ感覚で==を使って問題がないです。
Javaの==による文字列比較の考え方
Javaの文字列同士で==を使って比較する使い方ですが、同じアドレスで同じ値の場合に等しいと判定されます。
いくつか例を見てみましょう。
まずは、異なる変数に同じ文字列を定義して比較した場合です。
//文字列同士を比較する
public void CompareStr2Str1() {
String str1 = "apple";
String str2 = "apple";
//通常の等号で比較してみる(等号の動作が正しければ「等しい」と表示される)
if(str1 == str2) {
System.out.println("等しい");
} else {
System.out.println("等しくない");
}
}
この場合の実行結果を見てみると・・・
等しいと判定されました。
これはどういうことかというと、Javaでは余計なメモリ容量を使わずに済むように、同じ値を定義した変数は同じアドレスを指すようにしているためです。
次に、以下のように書き方を変えて比較してみることにします。
//文字列同士を比較する
public void CompareStr2Str2() {
String str1 = "apple";
String str2 = ""+ "apple";
//通常の等号で比較してみる(等号の動作が正しければ「等しい」と表示される)
if(str1 == str2) {
System.out.println("等しい");
} else {
System.out.println("等しくない");
}
}
結果を見てみますと・・
やはり等しいと結果が出ました。
定義の段階で文字列を結合しても最終的にはstr1とstr2で同じ”apple”という文字列を定義したことになるため、同じアドレスを参照するようになるようです。
次に2つの文字列を定義する変数の片方のアドレスを意図的に変えて==で判定するとどうなるかを見てみましょう。
//文字列同士を比較する
public void CompareStr2Str3() {
String str1 = "apple";
String str2 = new String("apple");
//通常の等号で比較してみる(等号の動作が正しければ「等しくない」と表示される)
if(str1 == str2) {
System.out.println("等しい");
} else {
System.out.println("等しくない");
}
}
結果を見てみますと・・
今度は等しくないという結果が出ました。
str1もstr2も同じ”apple”という文字列で定義しているのですが、アドレスが違うため等しくないと判定されています。
では、異なるアドレスの文字列を比較するにはどうすればいいでしょうか?
次の章で説明します。
文字列同士の比較はequals()を使う
異なるアドレスの文字列の値を比較する場合は、同じ値であっても==で比較すると等しくないと判定されることが前の章でお分かりいただけたかと思います。
では、異なるアドレスの文字列で値が等しいかどうかを判定する場合、どうすればいいでしょうか?
結論から先に申し上げるとequals()により判定します。
構文は以下のようになります。
比較したい文字列の変数1.equals(比較したい文字列の変数2)
たとえば、先ほど等しくないと判定されたif文をequals()を用いて書き換えると以下のようになります。
//文字列同士を比較する
public void CompareStr2Str4() {
String str1 = "apple";
String str2 = new String("apple");
//equalsで比較してみる(等号の動作が正しければ「等しい」と表示される)
if(str1.equals(str2)) {
System.out.println("等しい");
} else {
System.out.println("等しくない");
}
}
この処理を実行してみると・・・
正しく等しいと判定されました。
ただし、このequals()ですが、気を付けないといけないことがあります。
それはequals()をつける変数の値がnullであれば比較が出来ず、エラーとなってしまうことです。
例えば以下のような比較をしてみることにしましょう。
//文字列とnullを比較する
public void CompareStr2Str5() {
String str1 = "apple";
String str2 = null;
//equalsで比較してみる(nullポインタ例外発生)
if(str2.equals(str1)) {
System.out.println("等しい");
} else {
System.out.println("等しくない");
}
}
str2がnullになっていますが、どうなるでしょうか?
結果としては以下のエラーが出てプログラムが停止してしまいました。
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "str2" is null at article10.Compare.CompareStr2Str5(Compare.java:58) at article10.Main.main(Main.java:9)
str2がnullであるため、nullPointerException(ポインタを指す先がnullになって参照できない場合に発生する例外)が起きてしまいました。
nullPointerExceptionはequals()を使うとよく見る例外で、この例外を防ぐためにはequals()をつける変数(上記ソースではstr2が該当します)がnullにならないよう、必ず値が入る状態にしておかなければなりません。
なお、if(str2.equals(str1))の部分をif(str1.equals(str2))に書き換えて、equals()の引数の文字列がnullになる場合は正しく「等しくない」と判定されますが、こちらも例外は起こらないものの、あまり好ましい比較方法ではありません。
比較を行った後に他のコードが書いてあれば、そこで引っかかってnullPointerExceptionが出る可能性があります。
文字列をequalsを使って比較する場合は変数がnullでないことをきちんと事前にチェックし、nullが入らない状態でequals()を使うなどの配慮が必要です。
文字列とnullの比較方法
前節の話の内容だけだと、文字列がnullであるかどうかの判定はどうすればいいのかと疑問に思う方もいるでしょう。
答えは単純で文字列とnullの比較は簡単で、==を使って比較をするだけです。
例えば以下の処理を実行してみることにします。
//文字列とnullを比較する
public void CompareStr2Str6() {
String str1 = null;
//nullが入った変数を通常の等号で比較してみる。等号の動作が正しければ「等しい」と表示される)
if(str1 == null) {
System.out.println("等しい");
} else {
System.out.println("等しくない");
}
}
上記の処理を実行してみると・・・
きちんと等しいと判定されました。
このnullであるかの判定はJavaのプログラムを書く際は良く使うことになるため、しっかりと覚えておきましょう。
まとめ
今回説明した内容をまとめます。
- 数値同士の比較は==を使って問題ない
- 文字列同士の比較は原則としてequlas()を使う
- equals()を付ける変数の値がnullであれば例外が発生するので、必ずnullにならないように考慮しなければならない。
- 変数とnullとの比較は==で比較が可能である
どれも基本的なことではありますが、文字列同士の比較で==を使ってしまうと、期待した動作にならないことが多く、バグを生み出す原因となります。
ですので、Javaで文字列同士の比較を行うのであれば、必ずequals()を使って比較するように習慣づけてほしいと思います。
今回の記事はここまでとなります。
また次回の記事でお会いしましょう。