Warum gibt es in Java kein String.Empty?

260

Ich verstehe, dass jedes Mal, wenn ich das String-Literal eingebe "", dasselbe String-Objekt im String-Pool referenziert wird.

Aber warum enthält die String-API kein a public static final String Empty = "";, sodass ich Verweise auf verwenden kann String.Empty?

Dies würde zumindest Kompilierungszeit sparen, da der Compiler wissen würde, auf den vorhandenen String zu verweisen, und nicht prüfen müsste, ob er bereits zur Wiederverwendung erstellt wurde, oder? Und ich persönlich denke, dass eine Verbreitung von String-Literalen, insbesondere von winzigen, in vielen Fällen ein "Code-Geruch" ist.

Gab es also einen großen Designgrund für kein String.Empty, oder haben die Sprachschöpfer meine Ansichten einfach nicht geteilt?

Tom Tresansky
quelle
5
Aidanc: Ich glaube , er bedeutet , Situationen , in denen Sie Dinge tun , wie outputBlah = "", und er zieht es wahrscheinlich something == String.Emptyüber something.Length > 0als auch (Sie einen Null - Check überspringen.)
Skurmedel
2
@Aidanc - Er suchte nach einem "leeren Mitglied" wie Collections.EMPTY_SET , nicht nach einer Funktion zum Überprüfen der Zeichenfolge "Leere".
Tim Stone
2
@Aidanc: Was dies inspiriert hat, ist eigentlich 'TextBox.setText ("");'.
Tom Tresansky
3
Es gibt eine String.isEmpty()Funktion ... warum willst du String.EMPTY?
Buhake Sindi
8
String.isEmpty()gibt keine leere Zeichenfolge zurück.
Steve Kuo

Antworten:

191

String.EMPTYist 12 Zeichen und ""ist zwei, und beide würden zur Laufzeit genau dieselbe Instanz im Speicher referenzieren. Ich bin mir nicht ganz sicher, warum String.EMPTYich Zeit beim Kompilieren sparen sollte, tatsächlich denke ich, dass es das letztere sein würde.

Insbesondere wenn man bedenkt, dass Strings unveränderlich sind, ist es nicht so, dass man zuerst einen leeren String abrufen und einige Operationen daran ausführen kann - am besten verwenden Sie einen StringBuilder(oder StringBufferwenn Sie threadsicher sein möchten) und verwandeln diesen in einen String.

Update
Von Ihrem Kommentar zur Frage:

Was das inspiriert hat, ist eigentlich TextBox.setText("");

Ich glaube, es wäre absolut legitim, eine Konstante in Ihrer entsprechenden Klasse bereitzustellen:

private static final String EMPTY_STRING = "";

Und verweisen Sie dann wie in Ihrem Code auf

TextBox.setText(EMPTY_STRING);

Auf diese Weise weisen Sie zumindest ausdrücklich darauf hin, dass Sie einen leeren String möchten, anstatt zu vergessen, den String in Ihrer IDE oder ähnlichem auszufüllen.

Noel M.
quelle
14
Ich werde dich immer noch +1, aber ich fühle mich schmutzig, weil du erwähnt hast, StringBuilderohne darüber zu sprechen, wie neun von zehn es völlig unangemessen ist, es zu verwenden, StringBuilderanstatt es zu verketten.
Randolpho
84
Ich bevorzuge eher string.empty, hauptsächlich weil es expliziter ist. Es gibt auch Raten-Situationen, in denen es schwieriger sein kann, "" und Dinge wie "'" visuell zu unterscheiden. Wie andere angemerkt haben, ist es letztendlich nur eines dieser bedeutungslosen Stilsachen, über die wir uns streiten können, wenn uns echte Arbeit langweilig ist. =)
JohnFx
@Nodel M: In Bezug auf die Kompilierungszeit würde ich annehmen, dass, wenn 2 Zeichenfolgenliterale in 2 verschiedenen Quelldateien mit demselben Zeichenfolgenwert definiert sind, der Compiler beim Aufrufen der zweiten eine Art Überprüfung durchführen muss, um dies herauszufinden. " hey, ich kenne diese Saite schon von hier drüben ". Ich bin zwar kein Experte im Java-Compiler, aber wie könnte das NICHT der Fall sein? Und ich würde denken, dass das Überspringen dieser Prüfung zu einer winzigen Verbesserung der Kompilierungszeiten führen würde.
Tom Tresansky
@Tom - Ich glaube, dass die String-Internierung zur Laufzeit und nicht zur Kompilierungszeit erfolgt. Wenn Sie also die leere Zeichenfolge als Konstante in einer anderen Datei haben, muss der Compiler auf diese Klasse verweisen, um sie in das String-Literal aufzulösen.
Noel M
1
@Randolpho Wenn Sie die String-Verkettung verwenden, verwenden Sie tatsächlich einen StringBuilder unter der Haube.
whiskeysierra
133

Verwenden org.apache.commons.lang.StringUtils.EMPTY

Jade
quelle
29
Sieht viel schöner und leichter zu lesen aus als ein leeres "". Ich hoffe es nicht nur mir.
Lakatos Gyula
2
@ LakatosGyula - Ich denke es könnte sein (nur du). Kompetente Java-Programmierer haben keine Probleme beim Lesen ""... und die meisten würden wahrscheinlich lautstark gegen die Verwendung von EMPTYprotestieren, außer in bestimmten Situationen, in denen EMPTYeine domänenspezifische Bedeutung hat. (Und in solchen Fällen gibt es wahrscheinlich einen passenderen Namen.)
Stephen C
14
@ LakatosGyula Es sind nicht nur Sie. Ich bin von Java zur .NET-Entwicklung übergegangen, und String.Empty war eine Funktion, die ich gerne im Framework gefunden habe. Ich mag die explizite Natur eines leeren Satzes von Zitaten.
Yohohoho
63
@StephenC Wenn ich ein leeres "" sehe, fällt mir als erstes ein, dass es ein Fehler ist, jemand die Funktion nicht beendet hat usw. Mit String.EMPTY weiß ich genau, dass der Entwickler beabsichtigt hat, einen leeren String zurückzugeben.
Lakatos Gyula
1
Auch hilfreich für all jene Zeiten, in denen der Linter sagt "benutze eine benannte Konstante anstelle von bla bla bla". Jeder Programmierer weiß, dass "" keine Magie ist, aber es ist besser, es dem Kunden nicht erklären zu müssen.
LizH
28

Wenn Sie mit einer leeren Zeichenfolge vergleichen möchten, ohne sich um Nullwerte kümmern zu müssen, können Sie Folgendes tun.

if ("".equals(text))

Letztendlich sollten Sie das tun, was Ihrer Meinung nach am klarsten ist. Die meisten Programmierer gehen davon aus, dass "" eine leere Zeichenfolge bedeutet, keine Zeichenfolge, in die jemand vergessen hat, etwas einzugeben.

Wenn Sie glauben, dass es einen Leistungsvorteil gibt, sollten Sie ihn testen. Wenn Sie nicht der Meinung sind, dass es sich lohnt, es selbst zu testen, ist dies ein guter Hinweis darauf, dass es sich wirklich nicht lohnt.

Es hört sich so an, als würden Sie versuchen, ein Problem zu lösen, das gelöst wurde, als die Sprache vor mehr als 15 Jahren entworfen wurde.

Peter Lawrey
quelle
1
Ich bin ziemlich spät zur Party, aber da Java-Strings unveränderlich sind, glaube ich, dass alle leeren Strings innerhalb einer JVM nur unterschiedliche Verweise auf dasselbe String-Objekt sind. Also einfach das Folgende ist auch richtig: if ("" == text)
Ajoy Bhatia
12
@AjoyBhatia Das Problem ist, dass Sie neue leere Zeichenfolgen erstellen können. if ("" == new String())ist falsch. Ein besserer Testif(text.isEmpty())
Peter Lawrey
1
@AjoyBhatia - Nur wenn die Zeichenfolgen interniert sind. stackoverflow.com/questions/10578984/what-is-string-interning
Davor
9

Wenn Sie wirklich eine String.EMPTY-Konstante möchten, können Sie in Ihrem Projekt eine statische Endklasse mit dem Namen "Constants" erstellen. Diese Klasse behält Ihre Konstanten bei, einschließlich der leeren Zeichenfolge ...

Mit der gleichen Idee können Sie ZERO, ONE int-Konstanten erstellen, die in der Integer-Klasse nicht vorhanden sind, aber wie ich bereits sagte, wäre es mühsam, zu schreiben und zu lesen:

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

Usw.

Benoit Courtine
quelle
8

Apache StringUtils behebt auch dieses Problem.

Fehler der anderen Optionen:

  • isEmpty () - nicht null sicher. Wenn die Zeichenfolge null ist, wird eine NPE ausgelöst
  • length () == 0 - wieder nicht null sicher. Berücksichtigt auch keine Leerzeichenfolgen.
  • Vergleich mit der LEER-Konstante - Möglicherweise nicht null-sicher. Leerzeichenproblem

Zugegeben, StringUtils ist eine weitere Bibliothek zum Herumschleppen, funktioniert jedoch sehr gut und spart viel Zeit und Aufwand beim Überprüfen auf Nullen oder beim ordnungsgemäßen Umgang mit NPEs.

Freiheit
quelle
3
Also ... es scheint, dass die einzig sichere Option der schreckliche Yoda-Zustand ist : "".equals(s)?
Lie Ryan
8

Sagen Sie nicht einfach "Speicherpool von Zeichenfolgen wird in der wörtlichen Form wiederverwendet, Groß- / Kleinschreibung geschlossen". Was Compiler unter der Haube tun, ist hier nicht der Punkt. Die Frage ist vernünftig, insbesondere angesichts der Anzahl der erhaltenen Stimmen.

Es geht um die Symmetrie , ohne sie sind APIs für Menschen schwieriger zu verwenden. Frühe Java-SDKs haben die Regel notorisch ignoriert und jetzt ist es etwas zu spät. Hier sind ein paar Beispiele auf meinem Kopf, zögern Sie nicht, Ihr "Lieblings" -Beispiel einzuspielen:

  • BigDecimal.ZERO, aber keine AbstractCollection.EMPTY, String.EMPTY
  • Array.length but List.size ()
  • List.add (), Set.add (), aber Map.put (), ByteBuffer.put () und StringBuilder.append (), Stack.push ()
Slawomir
quelle
Auch wenn Sie den List-Parameter length () benannt haben, benötigen Sie die Klammer, da es sich um eine Methode handelt. Array.length ist eine öffentliche endgültige Variable, die nur funktioniert, weil Arrays unveränderlich sind. Sie hätten also immer noch Array.length und List.length (). Ich würde argumentieren, dass dies verwirrender und fehleranfälliger ist. Was .append () und .push () betrifft, so haben sie, obwohl sie ähnliche Aufgaben ausführen, einen angemessenen Namen. Das Anhängen des Strings ist genau das, was Sie tun, aber Sie "hängen" keinen Stapel an, Sie drücken und Pop-Werte. Und StringBuilder.push () würde StringBuilder.pop () implizieren, was nicht möglich ist.
Craig Parton
Ausgehend von Vorlagen / Generika helfen konsistente Schnittstellen auch bei Algorithmen. Wenn ein Algorithmus eine Länge einer Sammlung benötigt, ist Länge (T) oder T. Länge () alles, was uns wichtig ist. In ähnlicher Weise kann das Hinzufügen am Ende eines Stapels, einer Liste oder einer Zeichenfolge durch ein universelles Hinzufügen () oder Anhängen () erfolgen. Sie haben erwähnt, dass das Array in Java ein unveränderlicher / eingebauter Typ mit einer Eigenschaft für die exponierte Länge ist. Das ist in Ordnung, es bedeutet nicht, dass der Compiler keinen Code für Länge (T) oder T. Länge () verarbeiten oder generieren kann. Kotlin generiert eine Reihe von intrinsischen Methoden für verschiedene Fälle.
Slawomir
Mit einer konsistent benannten length () -Methode können wir jedoch nur die Länge überprüfen. Wie nützlich ist das? Wenn Sie Listen und Arrays abstrahieren möchten, um sie entweder über eine Schnittstelle nutzbar zu machen, benötigen Sie auch eine konsistente Methode zum Lesen oder Schreiben von Daten. Jetzt müssen Sie die Methoden get (), set () und add () generieren. Im Wesentlichen erstellen Sie eine weniger funktionale Listenansicht des Arrays. Warum sollte man das Rad neu erfinden, da Arrays.asList () verfügbar, einfach zu bedienen und leicht ist? Arrays, Listen, StringBuilder und Stapel haben alle einen bestimmten Zweck. Scheint besser, Ihre Benutzeroberfläche so zu gestalten, dass sie die beste Passform bietet.
Craig Parton
5

Alle diese ""Literale sind dasselbe Objekt. Warum all diese zusätzliche Komplexität machen? Die Eingabe ist nur länger und weniger klar (die Kosten für den Compiler sind minimal). Da Javas Zeichenfolgen unveränderliche Objekte sind, besteht keine Notwendigkeit, zwischen ihnen zu unterscheiden, außer möglicherweise aus Effizienzgründen, aber mit dem leeren Zeichenfolgenliteral ist das keine große Sache.

Wenn Sie wirklich eine EmptyStringKonstante wollen , machen Sie es selbst. Aber alles, was es tun wird, ist, noch ausführlicheren Code zu fördern. Dies wird niemals von Nutzen sein.

Donal Fellows
quelle
27
x = String.Emptyvermittelt Absicht besser als x = "". Letzteres könnte eine versehentliche Unterlassung sein. Zu sagen, dass es niemals einen Nutzen gibt, ist falsch.
Jeffrey L Whitledge
@ Jeffrey: Ich glaube nicht, dass ich besonders einverstanden bin. Es ist eines dieser Dinge, bei denen es wohl keine feste Regel gibt.
Donal Fellows
Ja, es ist wichtig darauf hinzuweisen, dass der Java-Compiler prüft, ob Zeichenfolgenliterale bereits vorhanden sind, bevor eine neue Instanz im Zeichenfolgenpool erstellt wird.
1.
1
@ Jeffrey - zu wissen, dass dies eine sehr alte und subjektive Diskussion ist. x = String.Emptyvermittelt Absicht, wahr. Angenommen, die Sprache liefert eine Konstante String.Empty. Wenn Sie auf etwas stoßen x = "", wissen Sie immer noch genau so viel über die Absicht, als ob es keine solche Konstante gäbe. Sie müssen sicherstellen, dass alle Stellen im Java-Code der Welt, an denen eine leere Zeichenfolge angegeben wurde, nicht verwendet ""werden, um den von Ihnen erwähnten Informationsgewinn zu erhalten. Ironischerweise verwendet C # eine Konstante und fördert deren Verwendung. Wie gesagt, ich weiß, dass es sich um eine sehr meinungsgebundene Diskussion handelt.
Chiccodoro
@chiccodoro - Ja, das stimmt. Deshalb sollte das leere String-Literal ""illegal sein, um Unfälle auszuschließen. Ich scherze nur!
Jeffrey L Whitledge
4

Um das zu ergänzen, was Noel M gesagt hat, können Sie sich diese Frage ansehen. Diese Antwort zeigt, dass die Konstante wiederverwendet wird.

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

String-Konstanten werden immer "interniert", so dass eine solche Konstante nicht wirklich benötigt wird.

String s=""; String t=""; boolean b=s==t; // true
James Black
quelle
1
Der Link ist tot.
Dieter
3

Ich verstehe, dass jedes Mal, wenn ich das String-Literal "" eingebe, dasselbe String-Objekt im String-Pool referenziert wird.
Es gibt keine solche Garantie. Und Sie können sich in Ihrer Anwendung nicht darauf verlassen, es liegt ganz bei jvm, zu entscheiden.

oder haben die Sprachschöpfer meine Ansichten einfach nicht geteilt?
Ja. Mir scheint es eine Sache mit sehr niedriger Priorität zu sein.

Nikita Rybak
quelle
6
Es gibt keine solche Garantie ... Nun, die JLS gibt an, dass dies der Fall sein sollte.
Tim Stone
@ Tim Nicht, wenn Sie nicht 'intern' anrufen. Es ist einfach, zwei gleich große Zeichenfolgen programmgesteuert zu erstellen und zu überprüfen.
Nikita Rybak
@Tim Wiederholen Sie beispielsweise a + = "a"; 100 mal, mach dasselbe mit b und überprüfe.
Nikita Rybak
5
Sie haben Recht, aber was Sie beschrieben haben, ist weder ein Zeichenfolgenliteral noch ein Ausdruck, dessen Ergebnis zum Zeitpunkt der Kompilierung garantiert werden kann (z. B. String username = "Bob" + " " + "Smith";). Programmgesteuert erstellte Zeichenfolgen haben keine Garantie für die Internierung, es sei denn, Sie rufen ausdrücklich an, intern()wie Sie angegeben haben. Das Szenario des OP beschreibt jedoch die Verwendung des leeren Zeichenfolgenliteral im ""gesamten Code. In diesem Fall würde eine automatische Internierung stattfinden.
Tim Stone
@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();Nun zeigen die aund bauf denselben Speicherort in PermGen. Siehe diesen Artikel
1ac0
1

Späte Antwort, aber ich denke, es fügt diesem Thema etwas Neues hinzu.

Keine der vorherigen Antworten hat die ursprüngliche Frage beantwortet. Einige haben versucht, das Fehlen einer Konstante zu rechtfertigen, während andere Wege aufgezeigt haben, wie wir mit dem Fehlen der Konstante umgehen können. Aber niemand hat eine zwingende Rechtfertigung zum Nutzen der Konstanten geliefert, so dass ihr Mangel immer noch nicht richtig erklärt wird.

Eine Konstante wäre nützlich, da sie verhindern würde, dass bestimmte Codefehler unbemerkt bleiben.

Angenommen, Sie haben eine große Codebasis mit Hunderten von Verweisen auf "". Jemand ändert eine davon, während er durch den Code blättert, und ändert sie in "". Eine solche Änderung hätte eine hohe Wahrscheinlichkeit, unbemerkt in die Produktion zu gelangen. Zu diesem Zeitpunkt könnte ein Problem auftreten, dessen Quelle schwer zu erkennen ist.

OTOH, eine Bibliothekskonstante mit dem Namen EMPTY, würde, wenn sie denselben Fehler aufweist, einen Compilerfehler für etwas wie EM PTY erzeugen.

Es ist immer noch besser, eine eigene Konstante zu definieren. Jemand könnte seine Initialisierung immer noch versehentlich ändern, aber aufgrund seiner weit verbreiteten Verwendung wäre es viel schwieriger, die Auswirkungen eines solchen Fehlers unbemerkt zu lassen als einen Fehler in einem einzelnen Anwendungsfall.

Dies ist einer der allgemeinen Vorteile, die Sie durch die Verwendung von Konstanten anstelle von Literalwerten erhalten. Normalerweise wird erkannt, dass Sie durch die Verwendung einer Konstante für einen Wert, der an Dutzenden von Stellen verwendet wird, diesen Wert einfach an nur einer Stelle aktualisieren können. Weniger häufig wird anerkannt, dass dies auch verhindert, dass dieser Wert versehentlich geändert wird, da eine solche Änderung überall angezeigt wird. Also, ja, "" ist kürzer als LEER, aber LEER ist sicherer als "".

Um auf die ursprüngliche Frage zurückzukommen, können wir nur spekulieren, dass die Sprachdesigner diesen Vorteil der Bereitstellung von Konstanten für häufig verwendete Literalwerte wahrscheinlich nicht kannten. Hoffentlich werden eines Tages String-Konstanten in Java hinzugefügt.

Laurentiu Cristofor
quelle
-16

Für diejenigen, die behaupten ""und String.Emptyaustauschbar sind oder die ""besser sind, liegen Sie sehr falsch.

Jedes Mal, wenn Sie so etwas wie myVariable = "" tun; Sie erstellen eine Instanz eines Objekts. Wenn das String-Objekt von Java eine leere öffentliche Konstante hätte, gäbe es nur eine Instanz des Objekts ""

Z.B: -

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 (11 einschließlich String.EMPTY) Zeiger auf 1 Objekt

Oder: -

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

10 Zeiger auf 10 Objekte

Dies ist ineffizient und kann in einer großen Anwendung von Bedeutung sein.

Möglicherweise ist der Java-Compiler oder die Java-Laufzeit effizient genug, um automatisch alle Instanzen von "" auf dieselbe Instanz zu verweisen, dies ist jedoch möglicherweise nicht der Fall und erfordert zusätzliche Verarbeitung, um diese Bestimmung vorzunehmen.

Antony Booth
quelle
9
Falsch, laut stackoverflow.com/questions/1881922/… wird die Zeichenfolge "" aus dem Zeichenfolgenpool wiederverwendet.
RealHowTo
1
Ich habe angegeben, dass es möglicherweise dasselbe Objekt wiederverwendet und wenn ja, immer noch weniger effizient ist, da es dieses Objekt (im Zeichenfolgenpool) finden muss. Wie irre ich mich also? Unabhängig davon gibt es mehrere Gründe, warum String.Empty überlegen ist, einschließlich der Vermeidung von Fehlern wie myVar = ""; und Lesbarkeit sowie die Leistungsverbesserung, die ich bereits angegeben habe. Es wird empfohlen, Konstanten zu verwenden, anstatt Zeichenfolgenliterale zu erstellen, wenn auch aus keinem anderen Grund. Es ist einfacher, Code zu pflegen.
Antony Booth
1
Ich bezweifle, dass Ihr Leistungsargument gültig ist, da das JLS angibt, dass eine Konstante beim Kompilieren als Literal behandelt wird ( docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10). 5 ). Die Lesbarkeit ist ein besseres Argument.
RealHowTo
3
@AntonySmith - Ich denke, Sie müssen Java ein wenig mehr lernen, oder vielleicht kennen Sie Ihren Fehler inzwischen. Java-Strings sind unveränderlich und befinden sich in einem Pool. Es gibt also nur EIN String-Objekt für "" in einer JVM, egal wie oft es im Code gefunden wird. Sie können überprüfen, ob eine Zeichenfolge leer ist, indem Sieif (text == "")
Ajoy Bhatia
2
Falsch. Dieser Kommentar sollte gelöscht werden.
Elad Tabak