その1 nullチェック
public static void main(String[] args) {
String str1 = null;
String str2 = "test";
System.out.println(str1.equals(str2));//実行1
System.out.println(str2.equals(str1));//実行2
}
実行1は、java.lang.NullPointerExceptionが発生します。
例外発生の原因は、str1にnullを入れてしまい、nullのオブジェクトからメソッドを呼び出してしまったことです。
nullでないstr2からメソッドを呼び出すと、例外が発生しなくなりfalseを返すようになります。
実行2の書き方は、str1がnullであっても例外が発生しないというメリットがありますが、異常系としてnullが入ることを想定せずに実装していた場合、コードミスに気づきにくいという短所があると思います。
nullチェックを意識するのであれば、例外処理で捕まえる方が安全かもしれません。
public static void main(String[] args) {
String str1 = null;
String str2 = "test2";
try {
System.out.println(str1.equals(str2));
}catch(NullPointerException ex) {
System.out.println("例外キャッチ");
}
}
その2 コンスタントプール
public static void main(String[] args) {
String str1 = "test1";
String str2 = "test1";
System.out.println(str1.equals(str2));//結果1
System.out.println(str1 == str2); //結果2
}
結果1はもちろんtrueになりますが、結果2はどうなるでしょうか?
結論、結果2もtrueになります。
これは、コンスタントプールという仕組みがあるためです。
文字リテラルは、プログラム中に頻繁に現れます。しかし、そのたびにStringのインスタンスを生成していては、メモリを大量に消費することになります。
もし、同じ文字列リテラルが再度登場すれば、定数用のメモリ空間にある文字列インスタンスへの参照が「使いまわし」されます。これがコンスタントプールという仕組みです。
このコンスタントプールは、文字列リテラルを使ったときだけ有効です。
new演算子を使って明示的に新しいインスタンスをつくることを記述した場合には、その都度インスタンスがつくられ、それぞれの変数が異なる参照を持ちます。
public static void main(String[] args) {
String str1 = new String("test");
String str2 = "test";
System.out.println(str1.equals(str2));//true
System.out.println(str1 == str2); //false
}
実際のプログラムではまずお目にかかりませんが、Java Silverとかでよく出てくるひっかけなので気をつけましょう。
その3 大文字小文字を区別しない判定
equalsIgnoreCaseメソッドを使うと、大文字小文字を区別せずに同値性を判定できます。
ただequalsに比べて出現頻度がかなり低いと思います。
public static void main(String[] args) {
String str1 = "abc";
String str2 = "ABC";
System.out.println(str1.equals(str2)); //false
System.out.println(str1.equalsIgnoreCase(str2));//true
}
以上