2009-02-10 17 views
30

Ho una domanda sul confronto di una stringa con la stringa vuota in Java. C'è una differenza, se confronto una stringa con la stringa vuota con == o equals? Per esempio:Confronto di una stringa con la stringa vuota (Java)

String s1 = "hi"; 

if (s1 == "") 

o

if (s1.equals("")) 

So che si dovrebbe confrontare le stringhe (e gli oggetti in generale) con equals, e non ==, ma mi chiedo se è importante per la stringa vuota.

+0

Non sta comparando la lunghezza migliore? Ritengo che la comparazione della lunghezza sia più ottimizzata della comparazione delle stringhe – Ravisha

+0

@Ravisha Internally, ['String.java''s] (http://www.docjar.com/html/api/java/lang/String.java.html)' il metodo equals' ha diverse ottimizzazioni: ** 1: ** Reference '==' confronto, ** 2: ** 'instanceof String' check prima del casting, e ** 3: ** confronto del valore della lunghezza prima di confrontare finalmente il personaggio delle stringhe per carattere. Quindi, per rispondere alla tua domanda, sì, il confronto della lunghezza è efficiente, ma il tuo codice dovrebbe fare affidamento su String.equals e non reinventare nessuna delle sue ruote. –

+0

@Patrick M. Se l'intenzione qui è di verificare la stringa vuota, preferisco confrontare la lunghezza. Piuttosto che un confronto. – Ravisha

risposta

26

Dipenderà se la stringa è letterale o meno. Se si crea la stringa con

new String("") 

Poi sarà mai soddisfatta "" con l'operatore di uguaglianza, come illustrato di seguito:

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 

In sostanza, si vuole usa sempre uguale()

+0

Può valere la pena di mostrare un esempio di codice uguale a(). – Kezzer

6

Una stringa, è una stringa, è una stringa, che si tratti della stringa vuota o meno. Utilizzare equals().

66
s1 == "" 

non è affidabile come test parità riferimento si oppone uguaglianza (e String non è strettamente canonica).

s1.equals("") 

è migliore ma può risentire delle eccezioni del puntatore nullo. Meglio ancora:

"".equals(s1) 

Nessuna eccezione di puntatore nullo.

MODIFICA: Ok, è stato chiesto il punto canonical form. Questo articolo lo definisce come:

Supponiamo di avere un set S di oggetti, con una relazione di equivalenza. Una forma canonica è data designando alcuni oggetti di S di essere "in canonica forma", tale che ogni oggetto in esame equivale esattamente un oggetto in forma canonica.

Per dare un esempio pratico: prendere l'insieme di numeri razionali (o "frazioni" sono comunemente chiamati). Un numero razionale consiste in un numeratore e un denomoinator (divisore), che sono entrambi numeri interi. Questi numeri razionali sono equivalenti:

3/2, 6/4, 24/16

nubmers razionali sono tipicamente scritti in modo tale che il MCD (massimo comune divisore) è 1. Quindi, tutti loro sarà semplificata 3/2. 3/2 può essere visualizzato come il modulo canonico di questo insieme di numeri razionali.

Quindi cosa significa programmare quando viene utilizzato il termine "forma canonica"? Può significare un paio di cose. Prendiamo ad esempio questa classe immaginaria:

public class MyInt { 
    private final int number; 

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

Il codice hash della classe MyInt è una forma canonica di quella classe perché per l'insieme di tutte le istanze di MyInt, si può prendere due elementi qualsiasi M1 e M2 e saranno obbedire la seguente relazione:

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

Questa relazione è l'essenza della forma canonica. Un modo più comune questo affiora è quando si utilizzano metodi di fabbrica su classi come:

public class MyClass { 
    private MyClass() { } 

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

istanze non possono essere istanziati direttamente poiché il costruttore è privato. Questo è solo un metodo di fabbrica. Quello che un metodo factory ti permette di fare è cose come:

  • Restituire sempre la stessa istanza (sottratto singleton);
  • Basta creare una nuova inattanza con ogni chiamata;
  • Restituzione di oggetti in forma canonica (maggiori dettagli in un secondo); oppure
  • qualunque cosa ti piaccia.

Fondamentalmente gli abstract metodo fabbrica oggetto la creazione e personalmente penso che sarebbe una caratteristica del linguaggio interessante per costringere tutti i costruttori di essere privato di far rispettare l'uso di questo modello, ma sto divagando.

Che cosa si può fare con questo metodo factory è cache di istanze che si crea tale che per ogni due istanze S1 e S2 obbediscono il seguente test:

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

Quindi, quando dico String non è strettamente canonica vuol dire che:

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

ma come altri hanno poitned out è possibile modificare questo utilizzando:

String s3 = new String("blah"); 

e possibilmente:

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

Quindi non si può fare affidamento sulla parità di riferimento completamente, quindi non si dovrebbe fare affidamento su di esso a tutti.

Come un avvertimento al modello sopra, devo sottolineare che la creazione di oggetti di controllo con costruttori privati ​​e metodi di fabbrica non garantisce l'uguaglianza di riferimento significa uguaglianza di oggetto a causa della serializzazione. La serializzazione aggira il normale meccanismo di creazione dell'oggetto. Josh Bloch tratta questo argomento in Effective Java (originariamente nella prima edizione quando parlava del pattern enum tipizzato che in seguito divenne un linguaggio in Java 5) e puoi aggirare il problema sovraccaricando il metodo readResolve() (privato). Ma è difficile. Anche i caricatori di classe influenzeranno il problema.

In ogni caso, questa è la forma canonica.

+1

+1 per una grande spiegazione. Ma potresti voler spiegare cosa significa "canonico" in questo contesto - che la JVM contiene una tabella di stringhe create in modo che non abbia bisogno di creare ripetutamente la stessa stringa. Uno dei pochi posti in cui Java ha un chiaro vantaggio in termini di prestazioni rispetto a C e C++. – rtperson

+0

Per C/C++, GCC ha almeno un'opzione di compilazione per riutilizzare le costanti di stringa. È abbastanza intelligente da supportare anche le sottostringhe. Non lo fa in fase di esecuzione, tuttavia (a meno che tu non abbia una libreria che esegue questa operazione, ad esempio utilizzando la condivisione implicita come Qt). – strager

+1

+1 per "" .equals (str) ... non posso credere che questo non mi sia mai venuto in mente. – Tom

9
"".equals(s) 

sembra essere l'opzione migliore, ma c'è anche Stringutils.isEmpty(s) contenuta nella biblioteca Apache Commons Lang

+6

Interessante, una chiamata in biblioteca che è più lunga e più oscura del codice che sostituisce. ;) –

+0

Anche se non aggiungerei commons-lang per questo se non lo stavo già usando per qualcos'altro, ma le probabilità sono che * lo * userei. Il puntatore nullo che evita la versione dell'istruzione mi ha sempre dato hive e odio anche il controllo per null way, quindi preferisco la versione StringUtils. –

+1

mentre è più lungo, non è più oscuro usare una chiamata di libreria come StringUtil.isNullOrEmpty (someString); e la ragione è che avere un nome lo rende molto più leggibile. il successo della performance è trascurabile, quindi è una vittoria. – Chii

10

E 'un po' di traverso dalla tua domanda iniziale, ma c'è sempre

if(s1.length() == 0) 

I crediamo che questo è equivalente al metodo isEmpty() dalla 1.6.

+1

Questo sarà soggetto a NullPointerException se la stringa è nullo. Puoi sempre usare if (s1! = Null && s1.length() == 0) ... In questo modo, il tuo condizionale cortocircuiterà dalla valutazione della lunghezza se s1 è nullo. – rtperson

+5

Sì, ma così sarà s1.isEmpty() o s1.equals (""). – eaolson

0

Date due stringhe:

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

-o -

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

L'operatore == eseguito su due oggetti controlli per l'identità di oggetto (che restituisce true se i due operatori restituiscono allo stesso oggetto istanza). Il comportamento effettivo di == applicato a java.lang.Strings non sembra sempre coerente a causa dell'internazionalizzazione di String.

In Java, le stringhe sono interned (almeno in parte a discrezione della JVM). In qualsiasi momento, s1 e s2 possono o non sono stati internati per essere lo stesso riferimento oggetto (supponendo che abbiano lo stesso valore.) Quindi s1 == s2 può o non può restituire true, basandosi esclusivamente sul fatto che s1 e s2 siano stati entrambi internati.

Rendere s1 e s2 uguali a vuoti Le stringhe non hanno alcun effetto su questo - possono ancora o non essere state internate.

In breve, == può o non può restituire vero se s1 e s2 hanno lo stesso contenuto. s1.equals (s2) è garantito per restituire true se s1 e s2 hanno lo stesso contenuto.

3

Utilizzare String.isEmpty() o StringUtils.isEmpty(String str) se è necessario un controllo Null.

+0

Vorrei che java avesse un String.Empty che si potesse impostare una stringa in Mi piace in C#. Renderà più comprensibile il metodo isEmpty() e renderà più semplice la pulizia per rendere una variabile uguale alla stringa vuota. – Knoxie

6

Risposta breve

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

mi assicuro s1 non è nullo e utilizzare isEmpty().

Nota: la stringa vuota "" non è una stringa speciale, ma conta come qualsiasi altro "valore".

Un po rispondere

Riferimenti a oggetti String dipenderà dal modo in cui vengono creati:

oggetti String creata usando l'operatore nuovo riferiscono sempre ad oggetti separati, anche se conservano la stessa sequenza di caratteri così:

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

oggetti stringa creata usando l'operatore = seguito da un valore compreso wh itin doppi apici (= "valore") sono memorizzati in un pool di oggetti String: prima di creare un nuovo oggetto nel pool, viene cercato un oggetto con lo stesso valore nel pool e fatto riferimento se trovato.

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

Lo stesso vale per le stringhe create racchiude un valore whitin virgolette ("valore"), in modo da:

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

String è uguale a controlli metodo per entrambi, è per questo che è sicuro di scrivere:

s1.equals(""); 

Questa espressione può gettare un NullPointerException se s1 == null, quindi, se non si controlla per null prima, è più sicuro di scrivere:

012.351.
"".equals(s1); 

Si prega di leggere anche How do I compare strings in Java?

Spero possa aiutare gli utenti non così esperti, che possono trovare altre risposte un po 'troppo complicato. :)

Problemi correlati