2013-08-04 17 views
8

consideri tale metodo:Devo memorizzare nella cache System.getProperty ("line.separator")?

@Override 
public String toString() 
{ 
    final StringBuilder sb = new StringBuilder(); 
    for (final Room room : map) 
    { 
     sb.append(room.toString()); 
     sb.append(System.getProperty("line.separator")); // THIS IS IMPORTANT 
    } 
    return sb.toString(); 
} 

System.getProperty("line.separator") può essere chiamato molte volte.

Devo memorizzare questo valore con public final static String lineSeperator = System.getProperty("line.separator") e utilizzare successivamente solo lineSeperator?

oppure System.getProperty("line.separator") è veloce quanto utilizzare un campo statico?

+0

Penso che System.getProperty debba cercare la chiave specificata ogni volta che la chiami. Non so se il compilatore faccia qualche ottimizzazione. Vediamo cosa suggeriscono le persone. – Fedy2

+0

Stai usando Java 7 o una versione precedente? – chrylis

+0

@chrylis Sto usando 6, sto pensando di iniziare con 7 (finora non vedo motivi validi per aggiornare ...). C'è qualche differenza tra 6 e 7 con questo 'getProperty()'? –

risposta

3

Vedo che la tua domanda presenta una falsa dicotomia. Non chiamerei mai getProperty ogni volta, né dichiarare un campo statico per esso. Vorrei semplicemente estrarlo su una variabile locale in toString.

@Override 
public String toString() 
{ 
    final StringBuilder sb = new StringBuilder(); 
    final String newline = System.getProperty("line.separator"); 
    for (final Room room : map) sb.append(room.toString()).append(newline); 
    return sb.toString(); 
} 

BTW Ho eseguito il benchmark della chiamata.Il codice:

public class GetProperty 
{ 
    static char[] ary = new char[1]; 
    @GenerateMicroBenchmark public void everyTime() { 
    for (int i = 0; i < 100_000; i++) ary[0] = System.getProperty("line.separator").charAt(0); 
    } 
    @GenerateMicroBenchmark public void cache() { 
    final char c = System.getProperty("line.separator").charAt(0); 
    for (int i = 0; i < 100_000; i++) ary[0] = (char)(c | ary[0]); 
    } 
} 

I risultati:

Benchmark      Mode Thr Cnt Sec   Mean Mean error Units 
GetProperty.cache   thrpt 1  3 5  10.318  0.223 ops/msec 
GetProperty.everyTime  thrpt 1  3 5  0.055  0.000 ops/msec 

L'approccio nella cache è più di due ordini di grandezza più veloci.

Si noti che l'impatto complessivo della chiamata a getProperty rispetto a tutta quella stringa è molto, molto improbabile che sia evidente.

+0

non è una buona risposta, se il caching è più veloce dovresti memorizzarlo in cache statico, e se chiamassi 'toString' più volte? – Enerccio

+0

La proprietà di sistema può cambiare da una chiamata all'altra. Soprattutto, l'utente potrebbe impostarlo solo una volta, ma dopo questa classe è già stata inizializzata. D'altra parte, il caching statico vincerà un accesso per chiamata 'toString' solo se il numero di elementi nella mappa è molto piccolo. Non si può sostenere che "non è una buona risposta" menzionando un'alternativa che ha solo diversi compromessi rispetto a questa. –

3

Non è necessario temere che il separatore di linee cambierà mentre il codice è in esecuzione, quindi non vedo alcun motivo per non memorizzarlo nella cache.

La memorizzazione nella cache di un valore è sicuramente più rapida dell'esecuzione ripetuta di una chiamata, ma la differenza sarà probabilmente trascurabile.

+1

Dipende se la chiamata è in linea durante l'ottimizzazione dell'hotspot :) –

+1

Oh, giusto, buon punto. Ma personalmente non mi piace fare affidamento su tali caratteristiche - non è meglio avere un codice che * già * sembra efficiente? – MightyPork

+0

Sono completamente d'accordo! Troppo spesso i colleghi sviluppatori fanno a meno dell'onesta inefficienza usando la scusa che verrà riparata durante il runtime. Sto solo facendo un punto. –

1

Se si è a conoscenza di un problema di prestazioni che si riferisce a questo, sì.

Se non si ha, quindi no, è improbabile che la ricerca abbia un sovraccarico sufficiente da importare.

Questo rientrerebbe in una o entrambe le categorie generali "micro-ottimizzazione" e "ottimizzazione prematura". :-)


Ma se siete preoccupati per l'efficienza, probabilmente avete un molto grande opportunità che il metodo toString sta rigenerando la stringa ogni volta. Se il numero toString viene chiamato molto, anziché memorizzare nella cache il terminatore di riga, memorizza nella cache la stringa generata e cancella ogni volta che cambia la mappa delle camere. Es .:

@Override 
public String toString() 
{ 
    if (cachedString == null) 
    { 
     final StringBuilder sb = new StringBuilder(); 
     final String ls = System.getProperty("line.separator"); 
     for (final Room room : map) 
     { 
      sb.append(room.toString()); 
      sb.append(ls); 
     } 
     cachedString = sb.toString(); 
    } 
    return cachedString; 
} 

... e quando i vostri mappa cambia, fanno

cachedString = null; 

Questo è un molto più scoppio per il dollaro (il dollaro è il sovraccarico di un campo aggiuntivo). Garantito che è per istanza piuttosto che per classe, quindi (fai riferimento ai commenti precedenti sull'efficienza) fallo solo se hai una buona ragione per farlo.

+1

L'ottimizzazione prematura può essere controproducente quando porta a codice "cattivo". In questo caso il codice sarà più veloce e leggibile (se non di più) quindi non credo che rientri in quella categoria ... – assylias

+2

@assylias: Innanzitutto, lasciami dire: ci sono poche persone che stanno peggio per l'ottimizzazione prematura di me. :-) Ma PO non è (solo) sulla creazione di codice errato. Si tratta di spendere tempo, energia e memoria per ottimizzare le cose che non necessitano di ottimizzazione, quando * potresti * usare quel tempo, energia e memoria per ottimizzare le cose che * hanno * bisogno di ottimizzare o aggiungere alle funzionalità. –

+0

@ T.J.Crowder Non ho nulla contro cui oppormi, ma in questo caso specifico estrarrei la variabile locale con prestazioni che non mi entrano nemmeno nella mente. –

2

Dal momento che è così facile da fare, perché no? Per lo meno l'implementazione di System.getProperty() dovrà eseguire una ricerca della tabella hash (anche se memorizzata nella cache internamente) per trovare la proprietà richiesta, quindi il metodo virtuale getString() verrà chiamato sull'oggetto risultante. Nessuno di questi è molto costoso, ma dovrà essere chiamato più volte. Per non parlare di molti String i provvisori verranno creati e avranno bisogno di GCing dopo.

Se si sposta questo fuori nella parte superiore del ciclo e si riutilizza lo stesso valore, si evitano tutti questi problemi. Quindi perche no?

+4

* "Poiché è così facile da fare, perché no?" * Perché se non importa, la creazione di campi statici aggiuntivi è una cattiva idea. Ogni classe che utilizza qualsiasi proprietà di sistema che non cambia conserva la propria copia di essa? E altre cose che non cambiano? Quando non si ottiene un chiaro guadagno in termini di prestazioni? No. Questo porta solo a ingombrare la memoria con informazioni ridondanti. –

+2

Sono d'accordo, e in realtà intendevo calcolarlo una volta, all'interno della funzione, prima di entrare nel ciclo. Non ho notato che l'OP stava usando un suggerimento usando un valore statico. –

+0

@ alex: Ah, sì, è diverso.:-) –

0

Se la proprietà di sistema è garantita per rimanere costante durante l'applicazione, può essere memorizzata nella cache, ma in generale si perderà la caratteristica della proprietà che sta cambiando il comportamento quando viene modificata.

Ad esempio un generatore di testo potrebbe utilizzare la proprietà per generare testo per windows o per linux e consentire la modifica dinamica della proprietà nell'applicazione, perché no?

In generale, l'acquisizione di una proprietà implica l'inutilità della funzione setProperty.

Problemi correlati