Java言語で文字列の値を比較したことがあるかと思います。Javaで文字列を比較するにはequalsを使う方法がありますが
- ==を使うのはだめなの?
- なぜequalsメソッドを使うの?
と言った声をお聞きします。文字列の比較についてわかりやすく解説をしていきます。この記事を見ればJava言語で文字列を比較した結果がどうなるかがわかります!
なお、Javaの記事については、こちらにまとめています。
文字列の比較
equalsメソッドで比較する
まずは文字列の比較方法であるStringクラスのequalsメソッドを使って文字列の比較をしてみましょう。
サンプルプログラム:
public class Main { public static void main(String[] args) { String foo = "foo"; String bar = "bar"; if (foo.equals(bar)) { System.out.println("fooとbarは一緒です。"); } else { System.out.println("fooとbarは違います。"); } } }
実行結果:
fooとbarは違います。
equlasメソッドは、引数に比較先となる文字列を指定することで、呼び出し元との文字列の値が一緒かどうかを比較します。このコードの場合では、変数fooの文字列をequalsメソッドを使って変数barの文字列と同じ文字列なのかをチェックしています。
==演算子で比較する
通常、値を比較する方法として「==」が用いられることがありますが、文字列の比較に置いてはこの方法は使うべきではありません。その原因はJavaの仕組みにあります。次のコードを見てみましょう。
サンプルプログラム:
public class Main { public static void main(String[] args) { String foo = "Orange"; String bar = new String("Orange"); if (foo == bar) { System.out.println("fooとbarは一緒です。"); } else { System.out.println("fooとbarは違います。"); } } }
実行結果:
fooとbarは違います。
あれ?おかしい?と思った方がいるかと思います。fooとbarは同じ値であるはずなのに「==」で比較しても違う文字列として扱われてしまいます。これはJavaの参照について解説する必要があります。
文字列は生成されるとメモリ上に文字列を保存しておくための場所(領域)が確保されます。そしてその確保した「場所」をfooやbarは保持しています。
つまり値を変数に保存しているわけではなく、場所を覚えておきfooやbarを使う際にその場所をたどって値を引っ張り出してくるという仕組みになっています。
この参照という仕組みがあるため「==」で比較した場合、文字列の値が一緒かどうかではなく文字列がメモリ上で格納されている場所が一緒かどうかという比較になります。そのため文字列の比較にはequalsメソッドを使うべきです。
では、続いて次のコードを見てみましょう。
サンプルプログラム:
public class Main { public static void main(String[] args) { String foo = "Orange"; String bar = "Orange"; if (foo == bar) { System.out.println("fooとbarは一緒です。"); } else { System.out.println("fooとbarは違います。"); } } }
実行結果:
fooとbarは一緒です。
あれれ?今度は一緒と表示されました。先程は場所同士の比較を行っているため値の比較をしているわけではないと解説しました。
その解説が正しければ、今回も文字列は同じであっても変数fooと変数barそれぞれがメモリが確保された場所を変数に保存する仕組みであるため、別々の場所が保存されているはず!となるわけですがこの場合は少し違います。
何が違うのかというと、変数fooを「Orange」で初期化後、barも「Orange」で初期化する際に、Java側が機転を利かせて同じメモリの場所を指すようにする仕組みがあるのです。
つまり「==」で比較するときには同じ場所を参照(比較)しているため一緒という扱いになるのです。少しややこしいかもしれませんが、参照については別途理解しておく必要があるでしょう。
参照型であるStringの値を比較する時は「==」を使わず、equalsメソッドを使いましょう!それに対し、同じ文字でもプリミティブ型であるcharの値は「==」で比較します。それは、プリミティブ型は値そのものが変数に保存されているためです。
nullと比較する上での注意点
前項まではequalsメソッドを使いましょうと言ってきました。
しかしこのequalsメソッドにも使い方に注意が必要です。どの部分に注意すべきかというと次のコードを見てみましょう。
サンプルプログラム:
public class Main { public static void main(String[] args) { String foo = null; String bar = "bar"; if (foo.equals(bar)) { System.out.println("fooとbarは一緒です。"); } else { System.out.println("fooとbarは違います。"); } } }
これを実行するとNullPointer例外が発生して実行を停止していまいます。なぜこのようなことが起きるかは1行目を見ればすぐわかりますね。
変数fooにnullが入っており、そのnullが入った変数を無理やり使おうとしてequlasを呼び出していますが、fooの値はnullであるため、呼び出しに失敗して例外が発生しています。
メソッドを呼び出す際にはその変数がnullでないかをチェックしなければなりません。変数がnullがどうかをチェックするには「==」を使用します。
サンプルプログラム:
public class Main { public static void main(String[] args) { String foo = null; String bar = "bar"; if (foo == null) { System.out.println("fooはnullです。"); } else { if (foo.equals(bar)) { System.out.println("fooとbarは一緒です。"); } else { System.out.println("fooとbarは違います。"); } } } }
実行結果:
fooはnullです。
「==」でnullかどうかをチェックし、nullでない場合に処理を行えばNullPointer例外が発生することはありません。
しかし、次のような書き方もあります。
サンプルプログラム:
public class Main { public static void main(String[] args) { String bar = null; if ("Orange".equals(bar)) { System.out.println("一緒です。"); } else { System.out.println("違います。"); } } }
実行結果:
違います。
この書き方では「定数(Orange)」を先に持ってきてその後にequalsメソッドを呼んでいます。こうすることで定数がnullということはないのでNullPointer例外で動作しなくなる可能性を回避することができます。
Objects.equalsを使う
文字列を比較するのに、Objects.equalsメソッドを使うという手段もあります。Objectsクラスはjava.utilパッケージに属します。
サンプルプログラム:
import java.util.Objects; public class Main { public static void main(String[] args) { String foo = null; String bar = "Orange"; if (Objects.equals(foo, bar)) { System.out.println("一緒です。"); } else { System.out.println("違います。"); } } }
実行結果:
違います。
このような形で使用します。これであればどちらかがnullだったとしてもNullPointer例外が発生することはありません。
しかしこの方法で両方の変数がnullだった場合、一緒の扱いとなるため文字列にnullが含まれることを良しとしない場合はnullチェックが必要でしょう。Objectsクラスのequalsメソッドについては、以下の記事でも詳しく解説しています!
equalsメソッドで比較をする方法総まとめ
equalsメソッドで比較する方法については、以下の記事でも詳しく解説しています!
まとめ
いかがでしょうか。文字列の比較にはStringクラスのequalsメソッドかObjects.equalsメソッドを使いましょう。また比較の際には文字列がnullであることを考慮しておかなければなりません。
文字列の比較について忘れてしまった場合はぜひこの記事を思い出して下さい。