web-dev-qa-db-ja.com

Javaで文字列を比較する方法

これまで私のプログラムでは==演算子を使ってすべての文字列を比較してきました。しかし、私はバグに遭遇し、代わりにそれらの1つを.equals()に変更し、そしてそれはバグを修正しました。

==は悪いですか?いつ使うべきで、使わないべきですか?違いは何ですか?

727
Nathan H

==は、参照が等しいかどうかをテストします(それらが同じオブジェクトかどうか)。

.equals()は値が等しいかどうかをテストします(それらが論理的に「等しい」かどうか)。

Objects.equals().equals()を呼び出す前にnullをチェックします。そのため、必要はありません(JDK 7以降で利用可能、 Guava でも利用可能)。

String.contentEquals() は、Stringの内容と任意のCharSequenceの内容(Java 1.5以降で使用可能)を比較します。

したがって、2つの文字列が同じ値を持っているかどうかをテストしたい場合は、おそらくObjects.equals()を使用したいでしょう。

// These two have the same value
new String("test").equals("test") // --> true 

// ... but they are not the same object
new String("test") == "test" // --> false 

// ... neither are these
new String("test") == new String("test") // --> false 

// ... but these are because literals are interned by 
// the compiler and thus refer to the same object
"test" == "test" // --> true 

// ... string literals are concatenated by the compiler
// and the results are interned.
"test" == "te" + "st" // --> true

// ... but you should really just call Objects.equals()
Objects.equals("test", new String("test")) // --> true
Objects.equals(null, "test") // --> false
Objects.equals(null, null) // --> true

あなたはほとんど いつも Objects.equals()を使いたいです。 rare あなたが know を扱っている状況では、 interned 文字列を扱っているので、あなたはcan==として使います。

JLS 3.10.5から。 文字列リテラル

さらに、文字列リテラルは常にクラスStringsameインスタンスを参照します。これは、文字列リテラル、より一般的には定数式( §15.28 )の値である文字列が、メソッドString.internを使って一意のインスタンスを共有するために "インターンされる"ためです。

同様の例が JLS 3.10.5-1 にもあります。

5319
Aaron Maenpaa

==はオブジェクト参照をテストし、.equals()は文字列値をテストします。

Javaは、同じインライン文字列が実際には同じオブジェクトであることを確認するために、いくつかの裏で作業を行うため、==が値を比較しているように見えることがあります。

例えば:

String fooString1 = new String("foo");
String fooString2 = new String("foo");

// Evaluates to false
fooString1 == fooString2;

// Evaluates to true
fooString1.equals(fooString2);

// Evaluates to true, because Java uses the same object
"bar" == "bar";

しかし、nullに注意してください。

==null文字列を正しく処理しますが、null文字列から.equals()を呼び出すと例外が発生します。

String nullString1 = null;
String nullString2 = null;

// Evaluates to true
System.out.print(nullString1 == nullString2);

// Throws a NullPointerException
System.out.print(nullString1.equals(nullString2));

fooString1がnullになる可能性があることがわかっている場合は、次のように書いて読者に伝えてください。

System.out.print(fooString1 != null && fooString1.equals("bar"));

以下はより短いですが、(Java 7から)nullをチェックすることはそれほど明白ではありません。

System.out.print(Objects.equals(fooString1, "bar"));
686
Whatsit

==はオブジェクト参照を比較します。

.equals()は文字列値を比較します。

以下のように、==が文字列値の比較を幻想にすることがあります。

String a="Test";
String b="Test";
if(a==b) ===> true

これは、文字列リテラルを作成すると、JVMは最初に文字列プールでそのリテラルを検索し、一致するものが見つかった場合は同じ文字列が新しい文字列に与えられるためです。これにより、次のようになります。

(a == b)===>真

                       String Pool
     b -----------------> "test" <-----------------a

ただし、次の場合に==は失敗します。

String a="test";
String b=new String("test");
if (a==b) ===> false

この場合、new String("test")のステートメントnewヒープはヒープ上に作成され、その参照はbに与えられるので、bはStringプールではなくヒープ上の参照を与えられます。

aはヒープ上のStringを指しているのに対し、bはStringプール内のStringを指しています。そのために私たちは得ます:

if(a == b)===> false。

                String Pool
     "test" <-------------------- a

                   Heap
     "test" <-------------------- b

.equals()は常にStringの値を比較するので、どちらの場合もそうです。

String a="Test";
String b="Test";
if(a.equals(b)) ===> true

String a="test";
String b=new String("test");
if(a.equals(b)) ===> true

だから.equals()を使うのは常に良いことです。

424
Ganesh

==演算子は、2つの文字列がまったく同じオブジェクトかどうかを確認します。

.equals()メソッドは2つの文字列が同じ値を持っているかどうかをチェックします。

217
Clayton

Javaの文字列は不変です。つまり、文字列を変更または修正しようとするたびに、新しいインスタンスが取得されます。元の文字列は変更できません。これらの文字列インスタンスをキャッシュできるようにこれが行われました。一般的なプログラムには多くの文字列参照が含まれており、これらのインスタンスをキャッシュすると、メモリ使用量を減らしてプログラムのパフォーマンスを向上させることができます。

文字列比較に==演算子を使用するときは、文字列の内容を比較しているのではなく、実際にはメモリアドレスを比較しています。両者が等しい場合はtrue、falseを返します。文字列と等しいのに対して文字列の内容を比較します。

問題は、すべての文字列がシステムにキャッシュされている場合、==がfalseを返すのに対し、equalsがtrueを返すのはどうしてですか。まあ、これは可能です。 String str = new String("Testing")のように新しい文字列を作成すると、キャッシュに同じ内容の文字列がすでに含まれている場合でも、キャッシュに新しい文字列を作成することになります。要するに"MyString" == new String("MyString")は常にfalseを返します。

Javaは文字列をキャッシュの一部にするために文字列に対して使用できる関数intern()についても話します。したがって、"MyString" == new String("MyString").intern()はtrueを返します。

注:==演算子は、2つのメモリアドレスを比較しているという理由だけで、equalsよりもはるかに高速ですが、コードがコード内に新しいStringインスタンスを作成していないことを確認する必要があります。さもなければあなたはバグに遭遇するでしょう。

172
Faisal Feroz
String a = new String("foo");
String b = new String("foo");
System.out.println(a == b); // prints false
System.out.println(a.equals(b)); // prints true

その理由を理解してください。 ==比較は参照を比較するだけだからです。 equals()メソッドは、内容を文字ごとに比較します。

aおよびbに対してnewを呼び出すと、それぞれが文字列テーブルの"foo"を指す新しい参照を取得します。参照は異なりますが、内容は同じです。

142
duffymo

ええ、それは悪いです...

==は、2つの文字列参照がまったく同じオブジェクトであることを意味します。 Javaがリテラルテーブルのようなものを保持しているため(これはそうである)、これは事実であると聞いたことがあるかもしれませんが、それは必ずしもそうではありません。いくつかの文字列は異なる方法でロードされ、他の文字列などから構築されます。そのため、2つの同一の文字列が同じ場所に格納されているとは限りません。

Equalsはあなたにとって本当の比較をします。

124
Uri

はい、==は文字列の比較には適していません(正規のものであることがわかっている場合を除き、実際には任意のオブジェクト)。 ==はオブジェクト参照を比較するだけです。 .equals()は等価性をテストします。文字列の場合、多くの場合それらは同じになりますが、あなたが発見したように、それは必ずしも保証されていません。

121
cletus

JavaにはStringプールがあり、その下でJavaがStringオブジェクトのメモリ割り当てを管理します。 Javaの文字列プールを参照してください

==演算子を使用して2つのオブジェクトをチェック(比較)するとき、アドレスの等価性を文字列プールと比較します。 2つのStringオブジェクトが同じアドレス参照を持つ場合はtrueを返し、それ以外の場合はfalseを返します。しかし、2つのStringオブジェクトの内容を比較したい場合は、equalsメソッドをオーバーライドする必要があります。

equalsは実際にはObjectクラスのメソッドですが、Stringクラスにオーバーライドされ、objectの内容を比較する新しい定義が与えられています。

Example:
    stringObjectOne.equals(stringObjectTwo);

しかし、注意してくださいそれは文字列の場合を尊重します。大文字と小文字を区別しないで比較したい場合は、StringクラスのequalsIgnoreCaseメソッドを使用する必要があります。

どれどれ:

String one   = "HELLO"; 
String two   = "HELLO"; 
String three = new String("HELLO"); 
String four  = "hello"; 

one == two;   // TRUE
one == three; // FALSE
one == four;  // FALSE

one.equals(two);            // TRUE
one.equals(three);          // TRUE
one.equals(four);           // FALSE
one.equalsIgnoreCase(four); // TRUE
112
Saurabh Agarwal

==はJava の中のオブジェクト参照を比較します、そしてそれはStringオブジェクトのための例外ではありません。

オブジェクトの実際の内容(Stringを含む)を比較するには、equalsメソッドを使用しなければなりません

==を使用した2つのStringオブジェクトの比較がtrueであることが判明した場合、それはStringオブジェクトがインターンされていて、Java仮想マシンがStringの同じインスタンスを指しているためです。同じ内容を含むStringオブジェクトを別のStringオブジェクトと比較して、==を使用してtrueとして評価することを期待してはいけません。

98
coobird

私は、学者からの回答に同意します。

しかし、あなたができることはあなたの非リテラル文字列でintern()を呼び出すことです。

Zacheratesの例から:

// ... but they are not the same object
new String("test") == "test" ==> false 

文字列でないリテラルの同等性がtrueである場合

new String("test").intern() == "test" ==> true 
98
pgras

.equals()はクラス内のデータを比較します(関数が実装されていると仮定して)。 ==はポインタの位置(メモリ内のオブジェクトの位置)を比較します。

両方のオブジェクト(PRIMITIVESについては話していない)が同じオブジェクトインスタンスを指している場合、==はtrueを返します。 2つのオブジェクトに同じデータが含まれている場合、.equals()はtrueを返します equals()とJavaの==

それはあなたを助けるかもしれません。

97
Matt Razza

2つのオブジェクト(この場合は文字列)がメモリ内の同じオブジェクトを参照しているかどうかにかかわらず、== reference equalityチェックを実行します。

equals()メソッドは2つのオブジェクトの contents または states が同じかどうかをチェックします。

明らかに==は高速ですが、2つのStringが同じテキストを保持しているかどうかを伝えたいだけの場合、多くの場合誤った結果をもたらすでしょう。

間違いなくequals()メソッドの使用をお勧めします。

性能について心配しないでください。 String.equals()の使用を推奨するいくつかのこと:

  1. String.equals()の実装は最初に参照の等価性をチェックし(==を使って)、2つの文字列が参照によって同じであれば、それ以上の計算は行われません!
  2. 2つの文字列参照が同じでない場合、String.equals()は次に文字列の長さをチェックします。 Stringクラスは文字列の長さを格納するため、これも高速な操作です。文字やコードポイントを数える必要はありません。長さが異なる場合、それ以上のチェックは実行されません。それらが等しくならないことがわかります。
  3. これまでに得られた場合にのみ、2つの文字列の内容が実際に比較されます。これは簡単な比較です。(2つの文字列の同じ位置に)不一致文字が見つかった場合、すべての文字が比較されるわけではありません。 )、それ以上の文字はチェックされません。

すべてのことを言って終わったとき、たとえ文字列がインターンであることを保証していたとしても、equals()メソッドを使うことはまだオーバーヘッドではないと思われるので、絶対にお勧めの方法です。効率的な参照チェックが必要な場合は、言語仕様と実装によって同じenum値が(参照によって)同じオブジェクトになることが保証されている場合はenumを使用してください。

93
icza

私のように、Javaを使い始めたときは、2つのStringインスタンスが等しいかどうかをテストするために "=="演算子を使いたかったのですが、良くも悪くも、これはJavaで正しい方法ではありません。

このチュートリアルでは、Java文字列を正しく比較するためのいくつかの異なる方法を紹介します。私が最もよく使う方法から始めます。このJava String比較チュートリアルの最後に、Javaストリングを比較するときに「==」演算子が機能しない理由についても説明します。

オプション1:equalsメソッドとのJava文字列比較 ほとんどの場合(おそらく95%の時間)、次のようにJava Stringクラスのequalsメソッドと文字列を比較します。

if (string1.equals(string2))

このString equalsメソッドは、2つのJava文字列を調べ、それらにまったく同じ文字列が含まれている場合、それらは等しいと見なされます。

次のテストを実行した場合、equalsメソッドを使用した簡単な文字列比較の例を見ると、2つの文字列はまったく同じではないため、等しいとは見なされません(文字の大文字と小文字は異なります)。

String string1 = "foo";
String string2 = "FOO";

if (string1.equals(string2))
{
    // this line will not print because the
    // Java string equals method returns false:
    System.out.println("The two strings are the same.")
}

しかし、2つの文字列がまったく同じ文字列を含んでいる場合、equalsメソッドはこの例のようにtrueを返します。

String string1 = "foo";
String string2 = "foo";

// test for equality with the Java string equals method
if (string1.equals(string2))
{
    // this line WILL print
    System.out.println("The two strings are the same.")
}

オプション2:equalsIgnoreCaseメソッドとの文字列比較

いくつかの文字列比較テストでは、文字列が大文字か小文字かを無視したいでしょう。大文字と小文字を区別しないで文字列の等価性をテストする場合は、次のようにStringクラスのequalsIgnoreCaseメソッドを使用します。

String string1 = "foo";
String string2 = "FOO";

 // Java string compare while ignoring case
 if (string1.equalsIgnoreCase(string2))
 {
     // this line WILL print
     System.out.println("Ignoring case, the two strings are the same.")
 }

オプション3:compareToメソッドとのJava文字列比較

Java文字列を比較するための、あまり一般的ではない3つ目の方法もあります。それは、StringクラスのcompareToメソッドを使用する方法です。 2つの文字列がまったく同じ場合、compareToメソッドは値0(ゼロ)を返します。これは、このString比較アプローチがどのようなものであるかを示す簡単な例です。

String string1 = "foo bar";
String string2 = "foo bar";

// Java string compare example
if (string1.compareTo(string2) == 0)
{
    // this line WILL print
    System.out.println("The two strings are the same.")
}

私はJavaにおけるこの同等性の概念について書いている間、Java言語は基本Java Objectクラスにequalsメソッドを含むことに注意することは重要です。独自のオブジェクトを作成していて、そのオブジェクトの2つのインスタンスが「等しい」かどうかを確認する手段を提供したい場合は、常にクラス内でこのequalsメソッドをオーバーライド(および実装)する必要があります。 String equalsメソッドでのこの等価/比較動作).

この ==、.equals()、compareTo()、およびcompare() を見てみるとよいでしょう。

81

関数:

public float simpleSimilarity(String u, String v) {
    String[] a = u.split(" ");
    String[] b = v.split(" ");

    long correct = 0;
    int minLen = Math.min(a.length, b.length);

    for (int i = 0; i < minLen; i++) {
        String aa = a[i];
        String bb = b[i];
        int minWordLength = Math.min(aa.length(), bb.length());

        for (int j = 0; j < minWordLength; j++) {
            if (aa.charAt(j) == bb.charAt(j)) {
                correct++;
            }
        }
    }

    return (float) (((double) correct) / Math.max(u.length(), v.length()));
}

テスト:

String a = "This is the first string.";

String b = "this is not 1st string!";

// for exact string comparison, use .equals

boolean exact = a.equals(b);

// For similarity check, there are libraries for this
// Here I'll try a simple example I wrote

float similarity = simple_similarity(a,b);
76
Khaled.K

==演算子は、2つの参照が同じオブジェクトを指しているかどうかを確認します。 .equals()は実際の文字列の内容(値)を確認します。

.equals()メソッドはクラスObject(全クラスのスーパークラス)に属しています。あなたはあなたのクラスの必要条件に従ってそれをオーバーライドする必要があります、しかしStringのためにそれはすでに実装されていて、そしてそれは2つのストリングが同じ値を持っているかどうかチェックします。

  • ケース1

    String s1 = "Stack Overflow";
    String s2 = "Stack Overflow";
    s1 == s2;      //true
    s1.equals(s2); //true
    

    理由:NULLなしで作成された文字列リテラルは、ヒープのpermgen領域の文字列プールに格納されます。したがって、s1とs2はどちらもプール内の同じオブジェクトを指しています。

  • ケース2

    String s1 = new String("Stack Overflow");
    String s2 = new String("Stack Overflow");
    s1 == s2;      //false
    s1.equals(s2); //true
    

    理由:newキーワードを使用してStringオブジェクトを作成した場合は、ヒープ上で個別のスペースが割り当てられます。

73
Aniket Thakur

==はオブジェクトの参照値を比較しますが、Java.lang.Stringクラスに存在するequals()メソッドはStringオブジェクトの内容を(別のオブジェクトと)比較します。

52
samkit shah

Stringを定義するとき、あなたはオブジェクトを定義すると思います。だからあなたは.equals()を使う必要があります。プリミティブデータ型を使用するときは==を使用しますが、String(および任意のオブジェクト)では.equals()を使用する必要があります。

49
fabricioflores

equals()メソッドがJava.lang.Objectクラスに存在し、オブジェクトの状態の等価性をチェックすることが期待されているならば!つまり、オブジェクトの内容です。 ==演算子は実際のオブジェクトインスタンスをチェックすることが期待されていますが同じであるかどうか。

str1str2という2つの異なる参照変数を考えます。

str1 = new String("abc");
str2 = new String("abc");

equals()を使う場合

System.out.println((str1.equals(str2))?"TRUE":"FALSE");

==を使用すると、出力はTRUEとなります。

System.out.println((str1==str2) ? "TRUE" : "FALSE");

これで、FALSEが出力として取得されます。なぜなら、両方のstr1str2は、同じ文字列コンテンツを共有していても、2つの異なるオブジェクトを指しているからです。 new String()のために毎回新しいオブジェクトが作成されます。

46
Rakesh KR

演算子 == は常に オブジェクト参照比較 を意味しますが、Stringクラス .equals() メソッドは コンテンツ比較 にオーバーライドされます。

String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1 == s2); // It prints false (reference comparison)
System.out.println(s1.equals(s2)); // It prints true (content comparison)
42
sham.y

compareTo()メソッドを使って2つの文字列を比較することもできます。 compareToの結果が0の場合、2つの文字列は等しく、それ以外の場合は比較される文字列は等しくありません。

==は参照を比較し、実際の文字列は比較しません。 new String(somestring).intern()を使用してすべての文字列を作成した場合は、==演算子を使用して2つの文字列を比較できます。それ以外の場合は、equals()またはcompareToメソッドしか使用できません。

Objectにはブール値を返すメソッド.equals()が含まれているので、すべてのオブジェクトに.equals()メソッドがあることが保証されています。さらに定義を定義する必要がある場合にこのメソッドをオーバーライドするのはサブクラスの仕事です。それがなければ(すなわち==を使って)、メモリアドレスだけが2つのオブジェクト間で等しいかどうかチェックされます。 Stringはこの.equals()メソッドをオーバーライドし、メモリアドレスを使用する代わりに、文字レベルで文字列の比較が等しいかどうかを返します。

重要な注意点は、文字列は1つの一括プールに格納されるため、文字列が作成されると、同じアドレスのプログラムに永久に格納されることです。文字列は変わらず、不変です。これが、大量の文字列処理を行う必要がある場合に、通常の文字列連結を使用することをお勧めしない理由です。代わりに、提供されているStringBuilderクラスを使用します。この文字列へのポインタは変更される可能性があることを忘れないでください。2つのポインタが同じであるかどうかを調べたい場合は、==を使用するのがよいでしょう。文字列自体はしません。

38
James

Javaでは、 “ ==” 演算子を使用して2つのオブジェクトを比較するときに、オブジェクトがメモリ内の同じ場所を参照しているかどうかを確認します。つまり、2つのオブジェクト名が基本的に同じメモリ位置を参照しているかどうかを確認します。

JavaのStringクラスは、実際にはObjectクラスのデフォルトのequals()実装をオーバーライドします。また、メソッドは、メモリ内の位置ではなく文字列の値のみをチェックするようにオーバーライドします。つまり、equals()メソッドを呼び出して2つのStringオブジェクトを比較すると、実際の文字シーケンスが等しい限り、両方のオブジェクトは等しいと見なされます。

==演算子は、2つの文字列がまったく同じオブジェクトかどうかを調べます。

.equals()メソッドは、2つの文字列が同じ値を持つかどうかを調べます。

34
Lijo