Perché non c'è String.Empty in Java?


266

Capisco che ogni volta che digito la stringa letterale "", viene fatto riferimento allo stesso oggetto String nel pool di stringhe.

Ma perché l'API String non include un public static final String Empty = "";, quindi potrei usare riferimenti a String.Empty?

Risparmierebbe il tempo di compilazione, come minimo, poiché il compilatore saprebbe fare riferimento alla stringa esistente e non dovrebbe controllare se è già stata creata per il riutilizzo, giusto? E personalmente penso che la proliferazione di stringhe letterali, specialmente minuscole, in molti casi sia un "odore di codice".

Quindi c'era un motivo di grande design dietro a String.Empty, o i creatori del linguaggio semplicemente non condividevano le mie opinioni?


5
Aidanc: Penso che egli intende situazioni in cui si fanno cose del genere outputBlah = "", e probabilmente preferisce something == String.Emptypiù di something.Length > 0così (si salta un controllo nullo.)
Skurmedel

3
@Aidanc - Stava cercando un "membro vuoto" come Collections.EMPTY_SET , non una funzione per controllare la stringa "vacuità".
Tim Stone

3
@Aidanc: Ciò che ha ispirato questo è in realtà 'TextBox.setText ("");'.
Tom Tresansky

3
C'è una String.isEmpty()funzione ... perché vorresti String.EMPTY?
Buhake Sindi

10
String.isEmpty()non restituisce una stringa vuota.
Steve Kuo

Risposte:


195

String.EMPTYè di 12 caratteri ed ""è di due ed entrambi farebbero riferimento esattamente alla stessa istanza in memoria in fase di esecuzione. Non sono del tutto sicuro del motivo per cui String.EMPTYfarebbe risparmiare tempo di compilazione, infatti penso che sarebbe quest'ultimo.

Soprattutto considerando che le Strings sono immutabili, non è che tu possa prima ottenere una stringa vuota ed eseguire alcune operazioni su di essa - meglio usare a StringBuilder(o StringBufferse vuoi essere thread-safe) e trasformarlo in una stringa.

Aggiorna
Dal tuo commento alla domanda:

Ciò che ha ispirato questo è in realtà TextBox.setText("");

Credo che sarebbe del tutto legittimo fornire una costante nella tua classe appropriata:

private static final String EMPTY_STRING = "";

E quindi referenziarlo come nel codice come

TextBox.setText(EMPTY_STRING);

In questo modo almeno sei esplicito che vuoi una stringa vuota, piuttosto che dimenticarti di compilare la stringa nel tuo IDE o qualcosa di simile.


17
Ti faccio ancora +1, ma mi sento sporco perché hai menzionato StringBuildersenza parlare di come nove volte su dieci sia totalmente inappropriato da usare StringBuilderpiuttosto che concatenare.
Randolpho

89
Tendo a preferire string.empty, soprattutto perché è più esplicito. Inoltre, ci sono situazioni in cui può essere più difficile differenziare visivamente "" e cose come "'". Alla fine, come altri hanno notato, è solo una di quelle cose di stile insignificanti che ci danno motivo di discutere quando siamo annoiati dal lavoro vero. =)
JohnFx

@Nodel M: Per quanto riguarda il tempo di compilazione, presumo che se ci sono 2 stringhe letterali definite in 2 diversi file sorgente con lo stesso valore di stringa, quando il compilatore raggiunge il 2 ° deve fare una sorta di controllo per capirlo " hey, so già di questa stringa da quaggiù ". Devo ammettere che non sono un esperto nel compilatore java, ma come potrebbe NON essere così? E penso che saltare quel controllo si tradurrebbe in un minuscolo miglioramento nei tempi di compilazione.
Tom Tresansky

1
@Randolpho Quando si utilizza la concatenazione di stringhe, si sta effettivamente utilizzando uno StringBuilder sotto il cofano.
whiskeysierra

1
E non dimenticare che per "" dobbiamo aggiungere // $ NON-NLS-1 $ che è di 13 caratteri + 2 da "". Quindi String.EMPTY vincerebbe sia in lunghezza che in estetica.
Yaza,

142

Uso org.apache.commons.lang.StringUtils.EMPTY


33
Sembra molto più carino e facile da leggere di un vuoto "". Spero non sia solo io.
Lakatos Gyula

3
@LakatosGyula - Penso che potrebbe essere (solo tu). I programmatori Java esperti non hanno problemi a leggere ""... e la maggior parte probabilmente si opporrebbe ad alta voce sull'uso di EMPTYtranne in situazioni specifiche in cui EMPTYha un significato specifico del dominio. (E in questi casi, probabilmente c'è un nome più appropriato.)
Stephen C

15
@LakatosGyula Non sei solo tu. Sono passato dallo sviluppo Java allo sviluppo .NET e String.Empty era una funzionalità che mi ha fatto piacere trovare nel framework. Mi piace la sua natura esplicita su un insieme vuoto di virgolette.
yohohoho

69
@StephenC Quando vedo un "" vuoto, la prima cosa che mi viene in mente è che si tratta di un bug, che qualcuno non ha terminato la funzione, ecc. Con String.EMPTY so esattamente che lo sviluppatore intendeva restituire una stringa vuota.
Lakatos Gyula

2
Utile anche per tutte quelle volte in cui il linter dice "usa una costante con nome invece di blah blah blah". Ogni programmatore sa che "" non è magia, ma è meglio non doverlo spiegare al cliente.
LizH

29

Se vuoi confrontare con una stringa vuota senza preoccuparti dei valori nulli, puoi fare quanto segue.

if ("".equals(text))

Alla fine dovresti fare ciò che credi sia più chiaro. La maggior parte dei programmatori presume che "" significhi una stringa vuota, non una stringa in cui qualcuno si è dimenticato di inserire qualcosa.

Se pensi che ci sia un vantaggio in termini di prestazioni, dovresti provarlo. Se non pensi che valga la pena di testarlo da solo, è una buona indicazione che non ne vale la pena.

Sembra che tu stia cercando di risolvere un problema che è stato risolto quando il linguaggio è stato progettato più di 15 anni fa.


1
Sono in ritardo per la festa ma, poiché le stringhe Java sono immutabili, credo che tutte le stringhe vuote all'interno di una JVM siano solo riferimenti diversi allo stesso oggetto String. Quindi anche semplicemente il seguente è corretto: if ("" == text)
Ajoy Bhatia

12
@AjoyBhatia Il problema è che puoi creare nuove stringhe vuote. if ("" == new String())è falso. Un test miglioreif(text.isEmpty())
Peter Lawrey il

1
@AjoyBhatia - Solo se le stringhe sono internate. stackoverflow.com/questions/10578984/what-is-string-interning
Davor

9

Se si desidera davvero una costante String.EMPTY, è possibile creare una classe finale statica di utilità denominata "Constants" (ad esempio) nel progetto. Questa classe manterrà le tue costanti, inclusa la stringa vuota ...

Nella stessa idea, puoi creare ZERO, ONE int costanti ... che non esistono nella classe Integer, ma come ho commentato, sarebbe un dolore scrivere e leggere:

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

Eccetera.


9

Non limitarti a dire "il pool di memoria delle stringhe viene riutilizzato nella forma letterale, maiuscolo chiuso". Quello che fanno i compilatori sotto il cofano non è il punto qui. La domanda è ragionevole, soprattutto visto il numero di voti positivi ricevuti.

Riguarda la simmetria , senza di essa le API sono più difficili da usare per gli esseri umani. I primi Java SDK notoriamente ignoravano la regola e ora è un po 'troppo tardi. Ecco alcuni esempi sopra la mia testa, sentiti libero di inserire il tuo esempio "preferito":

  • BigDecimal.ZERO, ma nessun AbstractCollection.EMPTY, String.EMPTY
  • Array.length ma List.size ()
  • List.add (), Set.add () ma Map.put (), ByteBuffer.put () e non dimentichiamo StringBuilder.append (), Stack.push ()

Anche se hai chiamato il parametro List length () hai ancora bisogno delle parentesi poiché è un metodo. Array.length è una variabile finale pubblica, che funziona solo perché gli array sono immutabili. Quindi avresti ancora Array.length e List.length (). Direi che è più confuso e incline all'errore. Per quanto riguarda .append () e .push (), sebbene eseguano attività simili, penso che abbiano un nome appropriato. Aggiungere la stringa è esattamente ciò che stai facendo, ma non "aggiungi" uno Stack, sposti e pop valori. E StringBuilder.push () implicherebbe StringBuilder.pop (), che non è possibile.
Craig Parton

Provenendo da modelli / generici, le interfacce coerenti aiutano anche con gli algoritmi. Se un algoritmo ha bisogno della lunghezza di una raccolta, length (T) o T.length () è tutto ciò che ci interessa. Allo stesso modo, l'aggiunta alla fine di una pila, di una lista o di una stringa può essere eseguita da un add () o append () universale. Hai detto che l'array in Java è di tipo immutabile / incorporato con una proprietà length esposta. Va bene, non significa che il compilatore non possa gestire o generare codice per length (T) o T.length (). Kotlin genera una serie di metodi intrinseci per vari casi.
Slawomir

Ma un metodo length () dal nome coerente ci consente solo di controllare la lunghezza. Quanto è utile? Se il tuo obiettivo è astrarre elenchi e array per renderli utilizzabili in qualche modo tramite un'interfaccia, hai anche bisogno di un modo coerente per leggere o scrivere dati. Quindi ora è necessario generare i metodi get (), set () e add (). In sostanza, stai creando una visualizzazione elenco meno funzionale dell'array. Dato che Arrays.asList () è disponibile, facile da usare e leggero, perché reinventare la ruota? Arrays, Lists, StringBuilders e Stacks hanno tutti uno scopo specifico. Sembra meglio progettare la tua interfaccia per utilizzare la soluzione migliore.
Craig Parton

8

Apache StringUtils risolve anche questo problema.

Mancanze delle altre opzioni:

  • isEmpty () - non protetto da null. Se la stringa è nulla, genera un NPE
  • length () == 0 - ancora una volta non nullo. Inoltre non tiene conto delle stringhe di spazi.
  • Confronto con la costante EMPTY: potrebbe non essere nullo. Problema di spazio bianco

Garantito StringUtils è un'altra libreria da trascinare, ma funziona molto bene e fa risparmiare un sacco di tempo e fatica a controllare i valori nulli o gestire con grazia gli NPE.


3
così ... sembra l'unica opzione sicura è la condizione terribile Yoda: "".equals(s)?
Lie Ryan

5

Tutti quei ""letterali sono lo stesso oggetto. Perché creare tutta quella complessità extra? È solo più lungo da digitare e meno chiaro (il costo per il compilatore è minimo). Poiché le stringhe di Java sono oggetti immutabili, non c'è mai bisogno di distinguerle, tranne forse come una cosa di efficienza, ma con la stringa vuota letterale non è un grosso problema.

Se vuoi davvero una EmptyStringcostante, fallo da solo. Ma tutto ciò che farà è incoraggiare un codice ancora più dettagliato; non ci sarà mai alcun vantaggio nel farlo.


28
x = String.Emptytrasmette l'intento meglio di x = "". Quest'ultima potrebbe essere un'omissione accidentale. Dire che non c'è mai alcun vantaggio non è corretto.
Jeffrey L Whitledge,

@ Jeffrey: non credo di essere particolarmente d'accordo. È una di queste cose in cui non ci sono regole ferree, suppongo.
Donal Fellows

Sì, è importante sottolineare che il compilatore java controlla se i letterali stringa esistono già prima di creare una nuova istanza nel pool di stringhe.
rds

1
@ Jeffrey - sapendo che questa è una discussione molto vecchia e soggettiva. x = String.Emptytrasmette intento, vero. Ma supponiamo che il linguaggio fornisca una costante String.Empty, quando incontri x = ""sai ancora esattamente tanto sull'intento come se non ci fosse una costante del genere. Dovresti garantire che tutti i posti nel codice Java del mondo in cui è stata intesa una stringa vuota non ""vengano utilizzati per ottenere il guadagno di informazioni che hai menzionato. Ironia della sorte, C # usa una costante e ne incoraggia l'uso, quindi come ho detto, so che è una discussione molto discutibile.
chiccodoro

@chiccodoro - Sì, è vero. Ecco perché la stringa letterale vuota ""dovrebbe essere illegale, per escludere incidenti. Sto scherzando!
Jeffrey L Whitledge


3

Capisco che ogni volta che digito il letterale String "", viene fatto riferimento allo stesso oggetto String nel pool String.
Non esiste una tale garanzia. E non puoi fare affidamento su di esso nella tua applicazione, spetta completamente a jvm decidere.

oppure i creatori del linguaggio semplicemente non hanno condiviso le mie opinioni?
Sì. A me sembra una cosa con una priorità molto bassa.


6
Non esiste una garanzia del genere ... Beh, la JLS afferma che dovrebbe essere così.
Tim Stone

@ Tim No, a meno che tu non faccia una chiamata "stagista". È facile costruire due stringhe grandi uguali a livello di codice e controllare.
Nikita Rybak

@Tim Ad esempio, ripetere a + = "a"; 100 volte, fai lo stesso con be controlla.
Nikita Rybak

5
Hai ragione, ma ciò che hai descritto non è una stringa letterale, né un'espressione il cui risultato può essere garantito in fase di compilazione (come String username = "Bob" + " " + "Smith";). Le stringhe create a livello di programmazione non hanno alcuna garanzia di essere internate, a meno che tu non chiami esplicitamente intern()come hai dichiarato. Lo scenario dell'OP descrive l'utilizzo della stringa letterale vuota in ""tutto il codice, che è un caso in cui si verificherebbe l'internamento automatico.
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();Ora ae bpuntano alla stessa posizione di memoria in PermGen. Vedi questo articolo
1ac0

2

Risposta tardiva, ma penso che aggiunga qualcosa di nuovo a questo argomento.

Nessuna delle risposte precedenti ha risposto alla domanda originale. Alcuni hanno tentato di giustificare la mancanza di una costante, mentre altri hanno mostrato modi in cui possiamo affrontare la mancanza della costante. Ma nessuno ha fornito una giustificazione convincente per il beneficio della costante, quindi la sua mancanza non è ancora adeguatamente spiegata.

Una costante sarebbe utile perché impedirebbe a determinati errori di codice di passare inosservati.

Supponiamo di avere una grande base di codice con centinaia di riferimenti a "". Qualcuno modifica uno di questi mentre scorre il codice e lo cambia in "". Un tale cambiamento avrebbe un'alta probabilità di passare inosservato nella produzione, a quel punto potrebbe causare qualche problema la cui fonte sarà difficile da rilevare.

OTOH, una costante di libreria denominata EMPTY, se soggetta allo stesso errore, genererebbe un errore del compilatore per qualcosa come EM PTY.

Definire la propria costante è ancora meglio. Qualcuno potrebbe ancora alterarne l'inizializzazione per errore, ma a causa del suo ampio utilizzo, l'impatto di un tale errore sarebbe molto più difficile da passare inosservato rispetto a un errore in un singolo caso d'uso.

Questo è uno dei vantaggi generali che si ottengono dall'utilizzo di costanti invece di valori letterali. Le persone di solito riconoscono che l'utilizzo di una costante per un valore utilizzato in dozzine di luoghi consente di aggiornare facilmente quel valore in un solo punto. Ciò che viene meno spesso riconosciuto è che ciò impedisce anche che quel valore venga modificato accidentalmente, perché un tale cambiamento si manifesterebbe ovunque. Quindi, sì, "" è più corto di EMPTY, ma EMPTY è più sicuro da usare di "".

Quindi, tornando alla domanda originale, possiamo solo ipotizzare che i progettisti del linguaggio probabilmente non fossero consapevoli di questo vantaggio di fornire costanti per valori letterali che vengono usati di frequente. Si spera che un giorno vedremo le costanti di stringa aggiunte in Java.


-16

Per coloro che affermano ""e String.Emptysono intercambiabili o ""è meglio, ti sbagli di grosso.

Ogni volta che fai qualcosa come myVariable = ""; stai creando un'istanza di un oggetto. Se l'oggetto String di Java avesse una costante pubblica EMPTY, ci sarebbe solo 1 istanza dell'oggetto ""

Per esempio: -

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 compreso String.EMPTY) Puntatori a 1 oggetto

O: -

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

10 puntatori a 10 oggetti

Ciò è inefficiente e in un'applicazione di grandi dimensioni può essere significativo.

Forse il compilatore Java o il runtime è abbastanza efficiente da puntare automaticamente tutte le istanze di "" alla stessa istanza, ma potrebbe non esserlo e richiede un'ulteriore elaborazione per effettuare tale determinazione.


10
Sbagliato, secondo stackoverflow.com/questions/1881922/… , la stringa "" verrà riutilizzata dal pool di stringhe.
RealHowTo

1
Ho affermato che potrebbe riutilizzare lo stesso oggetto e, in tal caso, è ancora meno efficiente, perché ha bisogno di trovare quell'oggetto (nel pool di stringhe), quindi come mi sbaglio? Indipendentemente da ciò, ci sono diversi motivi per cui String.Empty è superiore, inclusa la prevenzione di errori come myVar = ""; e leggibilità così come il miglioramento delle prestazioni che ho già affermato. È buona norma usare le costanti invece di creare stringhe letterali, se non altro; è più facile mantenere il codice.
Antony Booth

1
Dubito che il tuo argomento sulle prestazioni sia valido perché il JLS dice che una costante verrà trattata come letterale in fase di compilazione ( docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10. 5 ). La leggibilità è un argomento migliore.
RealHowTo

3
@AntonySmith - Immagino che tu debba studiare Java un po 'di più o forse ormai conosci il tuo errore. Le stringhe Java sono immutabili e in un pool. Quindi c'è solo UN oggetto String per "" in una JVM, non importa quante volte si trova nel codice. Puoi verificare se una stringa è vuota facendoif (text == "")
Ajoy Bhatia

2
Sbagliato. Questo commento dovrebbe essere cancellato.
Elad Tabak
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.