web-dev-qa-db-ja.com

文字列と空の文字列の比較(Java)

Javaでの文字列と空の文字列の比較について質問があります。 ==またはequalsで空の文字列と文字列を比較すると、違いはありますか?例えば:

String s1 = "hi";

if (s1 == "")

または

if (s1.equals("")) 

文字列(およびオブジェクト全般)を==ではなくequalsと比較する必要があることは知っていますが、空の文字列にとって重要かどうかは疑問です。

32
user42155
s1 == ""

オブジェクトの等価性ではなく参照の等価性をテストするため、信頼性がありません(Stringは厳密には標準ではありません)。

s1.equals("")

優れていますが、nullポインタ例外が発生する可能性があります。さらに良いのは:

"".equals(s1)

NULLポインター例外はありません。

EDIT:わかりました、ポイントは 標準形式 について尋ねられました。この記事では、次のように定義しています。

等価関係を持つオブジェクトのセットSがあるとします。正規形は、Sの一部のオブジェクトを「正規形」に指定することによって与えられます。そのため、検討中のすべてのオブジェクトは、正規形の1つのオブジェクトとまったく同じです。

実用的な例を挙げましょう:有理数のセットを取ります(または「分数」は一般に呼ばれます)。有理数は、分子と分母(除数)で構成されます。どちらも整数です。これらの有理数は同等です。

3/2、6/4、24/16

Rational nubmerは通常、gcd(最大公約数)が1になるように記述されます。したがって、それらはすべて3/2に簡略化されます。 3/2は、有理数のこのセットの正規形と見なすことができます。

それでは、「標準形式」という用語が使用されている場合、プログラミングでは何を意味しますか?それはいくつかのことを意味します。たとえば、この架空のクラスを考えてみましょう。

public class MyInt {
  private final int number;

  public MyInt(int number) { this.number = number; }
  public int hashCode() { return number; }
}

クラスMyIntのハッシュコードは、そのクラスの標準形式です。MyIntのすべてのインスタンスのセットに対して、任意の2つの要素m1およびm2を取得でき、次の関係に従うためです。

m1.equals(m2) == (m1.hashCode() == m2.hashCode())

その関係は、標準形式の本質です。これが発生するより一般的な方法は、次のようなクラスでファクトリメソッドを使用する場合です。

public class MyClass {
  private MyClass() { }

  public MyClass getInstance(...) { ... }
}

コンストラクターはプライベートであるため、インスタンスを直接インスタンス化することはできません。これは単なるファクトリメソッドです。ファクトリメソッドでできることは次のようなものです。

  • 常に同じインスタンス(抽象化されたシングルトン)を返します。
  • 呼び出しごとに新しいインスタンスを作成するだけです。
  • オブジェクトを正規形で返します(これについては後ほど説明します)。または
  • 君が好きなものならなんでも。

基本的に、ファクトリメソッドはオブジェクトの作成を抽象化し、個人的には、このパターンの使用を強制するためにすべてのコンストラクタをプライベートにすることは興味深い言語機能になると思いますが、私は脱線します。

このファクトリメソッドでできることは、作成したインスタンスをキャッシュして、2つのインスタンスs1およびs2に対して次のテストに従うようにすることです。

(s1 == s2) == s1.equals(s2)

したがって、Stringが厳密に標準的ではないと言うときは、次のことを意味します。

String s1 = "blah";
String s2 = "blah";
System.out.println(s1 == s2); // true

しかし、他の人が指摘したように、次を使用してこれを変更できます。

String s3 = new String("blah");

そしておそらく:

String s4 = String.intern("blah");

したがって、参照の平等に完全に依存することはできないため、まったく参照することはできません。

上記のパターンの注意点として、プライベートコンストラクターとファクトリメソッドを使用してオブジェクトの作成を制御しても、参照の等価性がシリアル化のためのオブジェクトの等価性を保証しないことを指摘する必要があります。シリアル化は、通常のオブジェクト作成メカニズムをバイパスします。 Josh BlochはこのトピックをEffective Java(元々は最初の版で彼が後にJava 5) (プライベート)readResolve()メソッドをオーバーロードすることで回避できますが、注意が必要です。クラスローダーも問題に影響します。

とにかく、それは標準的な形式です。

68
cletus

文字列がリテラルかどうかに依存します。で文字列を作成する場合

new String("")

次に、以下に示すように、等号演算子と「」が一致することはありません。

    String one = "";
    String two = new String("");
    System.out.println("one == \"\": " + (one == ""));
    System.out.println("one.equals(\"\"): " + one.equals(""));
    System.out.println("two == \"\": " + (two == ""));
    System.out.println("two.equals(\"\"): " + two.equals(""));

-

one == "": true
one.equals(""): true
two == "": false
two.equals(""): true

基本的に、常にequals()を使用します

26
tddmonkey

それはあなたの元の質問から少し横向きですが、常にあります

if(s1.length() == 0)

これは1.6のisEmpty()メソッドと同等だと思います。

10
eaolson
_"".equals(s)
_

最適なオプションのようですが、Apache commons langライブラリにはStringutils.isEmpty(s)も含まれています

9
Raibaz

短い答え

s1 == ""         // No!
s1.equals("")    // Ok
s1.isEmpty()     // Ok: fast (from Java 1.6) 
"".equals(s1)    // Ok: null safe

S1がnullではないことを保証し、isEmpty()を使用します。

注:空の文字列「」は特別な文字列ではありませんが、他の「値」としてカウントされます。

少し長めの答え

Stringオブジェクトへの参照は、作成方法によって異なります。

演算子newを使用して作成された文字列オブジェクトは、同じ文字列を格納している場合でも、常に個別のオブジェクトを参照します。

String s1 = new String("");
String s2 = new String("");
s1 == s2 // false

演算子=に続けて二重引用符で囲まれた値(= "value")を使用して作成された文字列オブジェクトは、作成前にStringオブジェクトのプールに保存されます。プール内の新しいオブジェクト、同じ値を持つオブジェクトがプール内で検索され、見つかった場合は参照されます。

String s1 = ""; // "" added to the pool
String s2 = ""; // found "" in the pool, s2 will reference the same object of s1
s1 == s2        // true

同じことは、二重引用符( "value")で値を囲むように作成された文字列にも当てはまります。

String s1 = "";  
s1 == "";        //true

String equalsメソッドは両方をチェックするため、安全に記述できます。

s1.equals("");

S1 == nullの場合、この式はNullPointerExceptionをスローする可能性があるため、以前にnullをチェックしない場合は、次のように記述する方が安全です。

"".equals(s1);

こちらもお読みください Javaで文字列を比較するにはどうすればよいですか?

他の回答が少し複雑すぎるかもしれない経験豊富なユーザーには役に立たないことを願っています。 :)

8
Linuslabo

文字列は、空の文字列であるかどうかにかかわらず、文字列であり、文字列です。 equals()を使用します。

6
Rob

Nullチェックが必要な場合は、 String.isEmpty() 、または StringUtils.isEmpty(String str) を使用します。

3
matsev

2つの文字列が与えられた場合:

String s1 = "abc";
String s2 = "abc";

-または-

String s1 = new String("abc");
String s2 = new String("abc");

2つのオブジェクトに対して実行される==演算子は、オブジェクトの同一性をチェックします(2つの演算子が同じオブジェクトインスタンスに戻る場合、trueを返します。)Java.lang.Stringsに適用される==の実際の動作は、ストリングインターン。

Javaでは、文字列は interned (少なくとも部分的にJVMの裁量で)です。任意の時点で、s1とs2は同じオブジェクト参照になるようにインターンされている場合とされていない場合があります同じ値を持ちます。)したがって、s1 == s2は、s1とs2の両方がインターンされたかどうかだけに基づいて、trueを返す場合とそうでない場合があります。

S1とs2を空の文字列に等しくしても、これには影響がありません。これらはまだ抑留されている場合とされていない場合があります。

つまり、==は、s1とs2の内容が同じ場合にtrueを返す場合と返さない場合があります。 s1.equals(s2)は、s1とs2の内容が同じ場合にtrueを返すことが保証されています。

0
Jared