JavaにString.Emptyがないのはなぜですか?


260

文字列リテラルを入力するたび""に、同じStringオブジェクトが文字列プールで参照されることを理解しています。

しかし、なぜString APIにはが含まれていないpublic static final String Empty = "";ので、への参照を使用できますString.Emptyか?

コンパイラは既存の文字列を参照することを知っており、再利用のためにすでに作成されているかどうかを確認する必要がないため、少なくともコンパイル時間を節約できます。そして個人的には、文字列リテラル、特に小さなリテラルの急増は、多くの場合「コードのにおい」だと思います。

String.Emptyの背後にグランドデザインの理由があったのか、それとも言語の作成者が私の見解を共有しなかったのか?


5
Aidanc:私は、彼はあなたのようなものを行う状況を意味だと思うoutputBlah = ""、と彼はおそらく好むsomething == String.Emptyオーバーsomething.Length > 0だけでなく(あなたがnullチェックを省略します。)
Skurmedel

2
@Aidanc-彼は、文字列「空」をチェックする関数ではなく、Collections.EMPTY_SETのような「空のメンバー」を探していました。
Tim Stone、

2
@Aidanc:これに影響を与えたのは、実際には 'TextBox.setText( "");'です。
トムトレサンスキー2010

3
String.isEmpty()関数があります...なぜあなたは欲しいのString.EMPTYですか?
ブハケシンディ

8
String.isEmpty()空の文字列は返しません。
Steve Kuo

回答:


191

String.EMPTYは12文字、""2 文字であり、どちらも実行時にメモリ内のまったく同じインスタンスを参照します。なぜString.EMPTYコンパイル時間を節約できるのか完全にはわかりませんが、実際には後者だと思います。

特にStringsが不変であることを考えると、最初に空の文字列を取得していくつかの操作を実行できるわけではありません-を使用してStringBuilder(またはStringBufferスレッドセーフにする場合)、それを文字列に変換するのが最適です。


コメントから質問への更新

これに触発されたのは TextBox.setText("");

私はあなたの適切なクラスで定数を提供することは完全に正当だと信じています:

private static final String EMPTY_STRING = "";

そして、あなたのコードのようにそれを参照してください

TextBox.setText(EMPTY_STRING);

この方法では、IDEまたは類似の文字列を入力するのを忘れたのではなく、少なくとも空の文字列が必要であることを明示します。


14
私はまだあなたを+1しますが、あなたはあなたStringBuilderが10回のうち9回StringBuilderは連結ではなく使用することがまったく不適切であるという話をせずに言ったので汚いです。
Randolpho

85
私はstring.emptyを好む傾向がありますが、それは主にそれがより明確だからです。また、「」と「 '」のようなものを視覚的に区別することが困難になるレート状況もあります。結局のところ、他の人が指摘しているように、それは私たちが実際の仕事に飽きているときに議論する飼料を与えるこれらの無意味なスタイルのものの1つにすぎません。=)
JohnFx

@Nodel M:コンパイル時間に関して、同じ文字列値を持つ2つの異なるソースファイルで2つの文字列リテラルが定義されている場合、コンパイラが2番目のリテラルにヒットすると、何らかのチェックを実行して、ねえ、私はすでにこのひもについてここから戻って知っています。」私は確かにJavaコンパイラの専門家ではありませんが、どうしてそうならないのでしょうか?そして、そのチェックをスキップすると、コンパイル時間はごくわずかに改善されると思います。
トムトレサンスキー2010

@Tom-文字列のインターンはコンパイル時ではなく実行時に行われると思います。したがって、実際に空の文字列が別のファイルに定数として含まれている場合、コンパイラはそのクラスを参照して文字列リテラルに解決する必要があります。
Noel M

1
@Randolpho文字列連結を使用する場合、実際には内部でStringBuilderを使用しています。
ウイスキーシエラ

133

使用する org.apache.commons.lang.StringUtils.EMPTY


30
空の ""よりも見栄えがよく、読みやすくなっています。私だけではないことを願っています。
Lakatos Gyula

2
@LakatosGyula-それは(あなただけ)かもしれないと思う。熟練したJavaプログラマは読むのに問題はありません""...そして、ほとんどのEMPTY場合EMPTY、ドメイン固有の意味を持つ特定の状況を除いて、ほとんどの人はの使用について大声で反対します。(そしてそのような場合、おそらくもっと適切な名前があります。)
スティーブンC

14
@LakatosGyulaそれはあなただけではありません。私はJavaから.NET開発に移行しましたが、String.Emptyはフレームワークで見つけた機能でした。空の引用符よりも明示的な性質が好きです。
yohohoho 2015

64
@StephenC空の ""が表示されると、バグ、誰かが関数を終了していないなど、最初に頭に浮かびます。String.EMPTYを使用すると、開発者が空の文字列を返すつもりであったことがわかります。
Lakatos Gyula

1
また、リンターが「何とか何とか何とか何とかではなく名前付き定数を使用する」と言っているすべての場合にも役立ちます。すべてのプログラマーは、「」が魔法ではないことを知っていますが、それを顧客に説明する必要がない方が良いでしょう。
LizH 2016年

28

null値を気にせずに空の文字列と比較したい場合は、次のようにします。

if ("".equals(text))

最終的には、自分が最も明確であると信じるものを実行する必要があります。ほとんどのプログラマーは、 ""が空の文字列を意味し、誰かが何かを入れ忘れた文字列ではないと想定しています。

パフォーマンス上の利点があると思われる場合は、テストする必要があります。自分でテストする価値がないと思われる場合は、実際に価値がないことを示しています。

15年以上前に言語が設計されたときに解決された問題を解決しようとするように思えます。


1
私はパーティーにかなり遅れましたが、Java文字列は不変であるため、JVM内のすべての空の文字列は、同じStringオブジェクトへの異なる参照であると思います。だから、単純に次のようにも正しいです: if ("" == text)
Ajoy Bhatiaは

12
@AjoyBhatia問題は、新しい空の文字列を作成できることです。if ("" == new String())は偽です。より良いテストif(text.isEmpty())
ピーターローリー

1
@AjoyBhatia-文字列がインターンされている場合のみ。stackoverflow.com/questions/10578984/what-is-string-interning
Davor

9

String.EMPTY定数が本当に必要な場合は、プロジェクトに「定数」という名前のユーティリティ静的最終クラス(たとえば)を作成できます。このクラスは、空の文字列を含む定数を維持します...

同じアイデアで、整数クラスに存在しないZERO、ONE int定数を作成できますが、私がコメントしたように、書き込みと読み取りは困難です。

for(int i=Constants.ZERO; ...) {
    if(myArray.length > Constants.ONE) {
        System.out.println("More than one element");
    }
}

等。


8

Apache StringUtilsもこの問題に対処しています。

他のオプションの失敗:

  • isEmpty()-nullセーフではありません。文字列がnullの場合、NPEをスローします
  • length()== 0-ここでもnullセーフではありません。また、空白文字列は考慮されません。
  • EMPTY定数との比較-nullセーフではない可能性があります。空白の問題

許可されたStringUtilsは、ドラッグする別のライブラリですが、非常にうまく機能し、nullのチェックや面倒なNullのチェックやNPEの適切な処理を節約できます。


3
そう...それは唯一の安全なオプションは恐ろしいヨーダ状態です:"".equals(s)
ライライアン

8

「文字列のメモリプールはリテラル形式で再利用され、大文字と小文字が区別される」とだけ言ってはいけません。コンパイラが内部で行うことはここでは重要ではありません。質問は、特にそれが受け取った賛成票の数を考えると合理的です。

対称性についてです。それがないと、APIは人間にとって使いづらくなります。初期のJava SDKは悪名高くこのルールを無視しており、今ではもう遅すぎます。ここに私の頭の上にいくつかの例があります。あなたの「お気に入り」の例に自由にチップを入れてください:

  • BigDecimal.ZERO、ただしAbstractCollection.EMPTY、String.EMPTYなし
  • Array.lengthがList.size()
  • List.add()、Set.add()ですが、Map.put()、ByteBuffer.put()で、StringBuilder.append()、Stack.push()を忘れないでください

Listパラメーターにlength()という名前を付けても、それはメソッドであるため、括弧が必要です。Array.lengthはpublic final変数であり、配列が不変であるためにのみ機能します。そのため、Array.lengthとList.length()がまだあります。私はそれがより混乱しやすく、間違いを起こしやすいと主張します。.append()と.push()については、同様のタスクを実行しますが、適切に名前が付けられていると思います。文字列の追加はまさにあなたがしていることですが、スタックを「追加」するのではなく、値をプッシュしてポップします。また、StringBuilder.push()は、StringBuilder.pop()を意味しますが、これは不可能です。
クレイグパートン

テンプレート/ジェネリックから来る、一貫したインターフェースはアルゴリズムにも役立ちます。アルゴリズムがコレクションの長さを必要とする場合は、length(T)またはT.length()だけで十分です。同様に、スタック、リスト、または文字列の末尾への追加は、普遍的なadd()またはappend()によって実行できます。Javaの配列は不変/組み込み型であり、長さプロパティが公開されています。それは問題ありません、それはコンパイラがlength(T)またはT.length()のコードを処理または生成できないことを意味しません。Kotlinは、さまざまなケースに対応する多くの組み込みメソッドを生成します。
Slawomir

ただし、一貫して名前が付けられたlength()メソッドでは、長さのみをチェックできます。それはどれほど役に立ちますか?リストと配列を抽象化してインターフェースを介して何らかの方法で使用できるようにすることが目標である場合は、データの読み取りまたは書き込みに一貫した方法も必要です。したがって、今度はget()、set()、およびadd()メソッドを生成する必要があります。基本的には、機能の少ない配列のリストビューを作成します。Arrays.asList()が利用可能で、使いやすく、軽量なので、ホイールを再発明するのはなぜですか?配列、リスト、StringBuilder、およびスタックにはすべて特定の目的があります。最適なものを使用するようにインターフェースを設計する方が良いようです。
クレイグパートン

5

これらの""リテラルはすべて同じオブジェクトです。なぜそんなに複雑なのですか?入力するのに時間がかかり、不明確になります(コンパイラーへのコストは最小限です)。Javaの文字列は不変オブジェクトであるため、おそらく効率的なものとして以外はそれらを区別する必要はまったくありませんが、空の文字列リテラルを使用することは大したことではありません。

本当にEmptyString定数が必要な場合は、自分で作成してください。しかし、それが行うことは、さらに冗長なコードを奨励することだけです。そうすることによる利益は決してありません。


27
x = String.Emptyよりも意図を伝えx = ""ます。後者は偶発的な省略である可能性があります。決して利益がないと言うのは間違っています。
ジェフリーLホイットリッジ

@ジェフリー:特にそうは思わない。これは、私が想定している厳格で迅速なルールがないこれらの事柄の1つです。
ドナルフェロー

はい、文字列プールに新しいインスタンスを作成する前に、Javaコンパイラが文字列リテラルがすでに存在するかどうかをチェックすることを指摘することが重要です。
RDS

1
@ジェフリー-これは非常に古く主観的な議論であることを知っています。x = String.Empty本当の意図を伝えます。しかし、言語が定数を提供していると仮定しString.Emptyます。遭遇しx = ""ても、そのような定数がなかった場合と同じように、意図について正確に理解しています。あなたが""言及する情報を得るために、空の文字列が意図された世界のJavaコードのすべての場所が使用しないことを保証する必要があります。皮肉なことに、C#は定数を使用し、その使用を奨励しているので、私が言ったように、私はそれが非常に意見の分かれる議論であることを知っています。
チッコドロ2014

@chiccodoro-はい、そうです。それが""事故を排除するために空の文字列リテラルが違法であるべき理由です。冗談です!
Jeffrey L Whitledge 2014

4

Noel Mが述べたことに補足すると、この質問を見ることができ、この答えは定数が再利用されていることを示しています。

http://forums.java.net/jive/message.jspa?messageID=17122

文字列定数は常に「インターン」されるため、実際にはそのような定数は必要ありません。

String s=""; String t=""; boolean b=s==t; // true

1
リンクが停止しています。
ダイエット

3

文字列リテラル「」を入力するたびに、同じStringオブジェクトが文字列プールで参照されることを理解しています。
そのような保証はありません。そして、あなたはあなたのアプリケーションでそれを信頼することはできません、それは決定するのは完全にjvm次第です。

あるいは、言語クリエーターは単に私の見解を共有しませんでしたか?
うん。私には、それは非常に優先度の低いもののようです。


6
そのような保証はありません ...まあ、JLS はそうであるべきであると述べています。
Tim Stone、

@Tim「インターン」コールを行わない限り、できません。プログラムで2つの等しい大きな文字列を作成してチェックするのは簡単です。
Nikita Rybak

@Timたとえば、+ = "a"を繰り返します。100回、bと同じようにしてチェックします。
Nikita Rybak

5
あなたは正しいですが、あなたが説明したのは文字列リテラルでも、コンパイル時に結果を保証できる式でもありません(などString username = "Bob" + " " + "Smith";)。プログラムで作成された文字列は、明示的に呼び出さない限り、インターンされる保証はありませんintern()。OPのシナリオでは""、コード全体で空の文字列リテラルを使用することについて説明していますが、これは自動インターンが発生する場合です。
ティムストーン

@Tim String a = ""; for(int i = 0; i < 100; i++) {a += "a";} String b = ""; for(int i = 0; i < 100; i++) {b += "b";} a.intern(); b.intern();次に、PermGen の同じメモリ位置abポイントします。この記事を
1ac0 2014年

1

遅い答えですが、それはこのトピックに何か新しいものを追加すると思います。

以前の回答のいずれも元の質問に回答していません。定数の欠如を正当化しようとする者もいれば、定数の欠如に対処する方法を示した者もいます。しかし、定数の利点について説得力のある正当化を提供した人は誰もいなかったため、定数の欠如はまだ適切に説明されていません。

定数は、特定のコードエラーが気付かれないようにするために役立ちます。

""への何百もの参照がある大きなコードベースがあるとします。誰かがコードをスクロールしながらこれらの1つを変更し、それを ""に変更します。このような変更は、気付かれずに本番環境に移行する可能性が高く、その時点で、ソースの検出が難しい問題が発生する可能性があります。

EMPTYという名前のライブラリ定数であるOTOHが同じエラーの影響を受ける場合、EM PTYなどのコンパイラエラーが生成されます。

独自の定数を定義することはさらに優れています。誰かがまだ初期化を誤って変更する可能性がありますが、その幅広い使用により、そのようなエラーの影響は、単一のユースケースのエラーよりも気付かれにくくなります。

これは、リテラル値の代わりに定数を使用することで得られる一般的な利点の1つです。人々は通常、何十もの場所で使用されている値に定数を使用すると、その値を1か所で簡単に更新できることを認識しています。あまり認められないのは、そのような変更がどこにでも表示されるため、これによりその値が誤って変更されることも防止されることです。したがって、はい、 ""はEMPTYよりも短いですが、 ""よりもEMPTYの方が安全です。

したがって、最初の質問に戻ると、言語デザイナーはおそらく、頻繁に使用されるリテラル値に定数を提供することのこの利点に気付いていなかったと推測できます。うまくいけば、いつかJavaで文字列定数が追加されるのを見ることになるでしょう。


-16

それらを主張し""String.Empty交換可能であるか、またはそれ""がよりよいのなら、あなたは非常に間違っています。

myVariable = "";のようなことをするたびに オブジェクトのインスタンスを作成しています。JavaのStringオブジェクトにEMPTYパブリック定数がある場合、オブジェクト ""のインスタンスは1つしかありません

例:-

String.EMPTY = ""; //Simply demonstrating. I realize this is invalid syntax

myVar0 = String.EMPTY;
myVar1 = String.EMPTY;
myVar2 = String.EMPTY;
myVar3 = String.EMPTY;
myVar4 = String.EMPTY;
myVar5 = String.EMPTY;
myVar6 = String.EMPTY;
myVar7 = String.EMPTY;
myVar8 = String.EMPTY;
myVar9 = String.EMPTY;

10(String.EMPTYを含む11)1つのオブジェクトへのポインタ

または:-

myVar0 = "";
myVar1 = "";
myVar2 = "";
myVar3 = "";
myVar4 = "";
myVar5 = "";
myVar6 = "";
myVar7 = "";
myVar8 = "";
myVar9 = "";

10個のオブジェクトへの10個のポインター

これは非効率的であり、大規模なアプリケーション全体で重要な場合があります。

おそらく、Javaコンパイラーまたはランタイムは、「」のすべてのインスタンスを自動的に同じインスタンスにポイントするのに十分効率的ですが、そうではなく、その決定を行うために追加の処理が必要になる場合があります。


9
誤って、stackoverflow.com / questions / 1881922 /…によると、 ""文字列は文字列プールから再利用されます。
RealHowTo

1
同じオブジェクトを再利用する可能性があると述べましたが、その場合も(文字列プール内で)そのオブジェクトを見つける必要があるため、効率が低下します。いずれにしても、myVar = "";などのエラーの防止など、String.Emptyが優れている理由はいくつかあります。読みやすさ、そしてすでに述べたパフォーマンスの向上。他に理由がない場合は、文字列リテラルを作成する代わりに定数を使用することをお勧めします。コードの保守が簡単です。
アントニーブース

1
JLSは定数がコンパイル時にリテラルとして扱われるとJLSが言っているので、パフォーマンス引数が有効であるとは思えませんdocs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10。 5)。読みやすさはより良い議論です。
RealHowTo

3
@AntonySmith-私はあなたがJavaをもう少し学ぶ必要があるか、おそらくあなたは今までにあなたのエラーを知っていると思います。Java文字列は不変であり、プール内にあります。したがって、JVM内の ""の文字列オブジェクトは、コード内で何回見つかっても、1つしかありません。文字列が空かどうかは、次のようにして確認できますif (text == "")
Ajoy Bhatia

2
違う。このコメントは削除する必要があります。
Elad Tabak
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.