2011-01-28 3 views
24

Mi sono imbattuto in una classe che include più usi di una stringa letterale, "pippo".Utilizzo di stringhe stringa identiche anziché di una variabile finale?

Quello che mi piacerebbe sapere, è quali sono i benefici e l'impatto (in termini di creazione di oggetti, utilizzo della memoria e velocità) di utilizzare questo metodo invece di dichiarare la stringa come definitiva e la sostituzione di tutti i letterali con la finale variabile?

Ad esempio (anche se ovviamente non è un reale utilizzo word):

private static final String FINAL_STRING = "foo"; 

public void stringPrinter(){ 
    for(int i=0;i<10;i++){ 
     System.out.println(FINAL_STRING); 
    } 
} 

versi:

public void stringPrinter(){ 
    for(int i=0;i<10;i++){ 
     System.out.println("foo"); 
    } 
} 

Che è preferibile e perché (assumendo che il valore di stringa rimarrà costante)?

Se il precedente esempio (secondo) risultasse in 10 oggetti String creati, la JVM si renderebbe conto che solo un singolo letterale viene effettivamente utilizzato e crea un riferimento singolo. In tal caso, c'è qualche vantaggio nel dichiarare la stringa come definitiva (come nel primo esempio)?

Se il codice interpretato fa sostituire la stringa letterale con un unico riferimento, vuol ancora applica se stesso letterale avviene in più di un posto:

public void stringPrinter(){ 
    for(int i=0;i<5;i++){ 
     System.out.println("foo"); // first occurence 
     System.out.println("foo"); // second occurence 
    } 
} 
+0

Non darei per scontato che lo sviluppatore precedente abbia scelto di ripetere i letterali usando una costante, sembra proprio pigrizia. –

+0

Stranamente, in realtà avevano dichiarato la costante ma non l'avevano usata. Quindi perché ero interessato alla possibile ragione. Ma d'accordo, penso che fosse solo pigrizia. – Mikaveli

risposta

26

Essi saranno esattamente lo stesso. Il letterale è internato (qualsiasi espressione costante di tempo di compilazione che si traduce in quella stringa condivide la stessa istanza di tutte le altre costanti/letterali) in entrambi i casi e un compilatore intelligente + runtime non dovrebbe avere problemi a ridurre entrambi all'esempio più ottimizzato.

Il vantaggio è maggiore nella manutenibilità. Se si desidera modificare il valore letterale, è necessario solo modificare un'occorrenza con una costante, ma sarà necessario cercare e modificare ogni istanza se sono inclusi in linea.

+0

Bel riferimento alla manutenibilità. –

+0

Tutte le risposte sono state molto utili, quindi il tuo è stato accettato per essere il primo. – Mikaveli

20

From the JLS
costanti in fase di compilazione di tipo String sono sempre "internati", in modo da condividere le istanze univoche, utilizzando il metodo String.Intern.

Quindi, no, ci sarà solo un oggetto stringa.

Come nota Mark, questa è strettamente la questione della manutenibilità e non delle prestazioni.

2

Questi valori letterali di stringa sono internalizzati, quindi non vengono creati nuovi oggetti String nel ciclo. Usare lo stesso letterale due volte potrebbe comunque essere un segnale per l'odore di codice, però; ma non in termini di velocità o utilizzo della memoria.

1

Nei casi che si stanno fornendo, credo che il motivo principale per averlo dichiarato come FINAL_STRING da qualche parte è assicurarsi che rimanga in una posizione centralizzata. Ci sarà sempre un'istanza di quella costante di stringa, ma il primo esempio è molto più semplice da mantenere.

letterali
3

Tutti stringa sono mantenuti in una cache stringa (questo è in tutte le classi)

Utilizzando una costante può rendere il codice più chiaro, che invia la stringa di un contesto e rendere il codice più facile da mantenere specialmente se stesso la stringa appare in più punti.

7

Il vantaggio non è nelle prestazioni, ma nella manutenibilità e affidabilità.

Lasciatemi fare un esempio reale di recente. Un programmatore ha creato una funzione che ha preso un parametro String che identificava il tipo di una transazione. Poi nel programma ha fatto il confronto tra stringhe contro questo tipo. Come:

if (type.equals("stock")) 
{ ... do whatever ... } 

Quindi ha chiamato questa funzione, passandogli il valore "Stock".

Si nota la differenza di lettere maiuscole? Nemmeno il programmatore originale. Si è rivelato un bug abbastanza sottile da capire, perché anche guardando entrambe le liste, la differenza di capitalizzazione non mi ha colpito.

Se invece aveva dichiarato uno statico finale, dicono

final static String stock="stock"; 

Poi la prima volta che cercava di passare in "Archivio" invece di "magazzino", avrebbe ottenuto un errore di compilazione.

Meglio ancora in questo esempio sarebbe stato quello di creare un enum, ma supponiamo che in realtà doveva scrivere la stringa su un file di output o qualcosa del genere quindi doveva essere una stringa.

Utilizzando statica finale fornisce almeno x vantaggi:

(1) Se si mis-scriverlo, si ottiene un errore di compilazione, piuttosto che un errore di run-time possibilmente-sottile.

(2) Uno statico può assegnare un nome fittizio a un valore. Che è più comprensibile:

if (employeeType.equals("R")) ... 

o

if (employeeType.equals(EmployeeType.RETIRED)) ... 

(3) Quando ci sono più valori correlati, si può mettere un gruppo di statica finale insieme alla parte superiore del programma, informando in tal modo futuri lettori quali sono tutti i valori possibili Ho avuto molte volte in cui ho visto una funzione confrontare un valore con due o tre letterali. E questo mi fa pensare: ci sono altri valori possibili, o è questo? (Meglio ancora è spesso avere un enum, ma questa è un'altra storia.)

+0

+1 Per una risposta chiara e completa e menzionando il potenziale beneficio per la leggibilità utilizzando nomi significativi per sostituire i letterali ambigui. – Mikaveli