2015-03-20 10 views
5

Nella pagina 140 di Java efficace si consiglia che una firma di metodo con un carattere jolly sia preferibile a una con un parametro di tipo che viene visualizzato solo una volta. Ad esempio,Tipi e prestazioni non elaborati

public static void swap(List<?> list, int i, int j) 

è preferibile

public static <T> void swap(List<T> list, int i, int j) 

Tuttavia non è possibile impostare un elemento di un List<?> essere nulla (tranne null) in modo efficace Java suggerisce scrivendo un metodo di supporto privato a fare la firma con un lavoro con caratteri jolly.

private static <T> void swapHelper(List<T> list, int i, int j) { 
    list.set(i, list.set(j, list.get(i))); 
} 

public static void swap(List<?> list, int i, int j) { 
    swapHelper(list, i, j); 
} 

Comunque ho guardato il codice sorgente per Collections.swap e abbiamo scoperto che il modo in cui hanno ottenuto intorno al problema List<?> era quello di utilizzare tipi prime.

public static void swap(List<?> list, int i, int j) { 
    final List l = list; 
    l.set(i, l.set(j, l.get(i))); 
} 

ci viene consigliato di non utilizzare i tipi di prime nel nuovo codice (tranne che in instanceof controlli). Quindi, vorrei sapere qual è la ragione qui? Esiste un vantaggio in termini di prestazioni nell'utilizzare i tipi non elaborati qui piuttosto che chiamare un metodo di supporto privato? In caso contrario, esistono esempi in cui l'utilizzo di tipi non elaborati può migliorare le prestazioni?

+0

I tipi di dati grezzi potrebbero essere evitati, usando 'Elenco ' invece di 'Elenco', ma quello sarebbe un cast non controllato, che in questo caso non è meno pericoloso del tipo non elaborato. – newacct

+0

* "(tranne che per i controlli di istanza)" * Questo non è vero. 'instanceof List ' va bene e preferito. ;) – Radiodef

+0

@Radiodef Non conforme all'efficace Java (2a edizione) pagina 114. –

risposta

6

L'ottimizzazione prematura è la radice di tutto il male. Molto probabilmente troverai che il compilatore JIT inline sia il tuo metodo swap che il tuo metodo swapHelper se si rivelano essere colli di bottiglia nelle prestazioni. In generale, il compilatore JIT Java è molto bravo nel rilevare i colli di bottiglia delle prestazioni.

Tuttavia, se si è interessati alle prestazioni, perché non scrivere un punto di riferimento per il metodo Collections.swap e la variante che utilizza un metodo di supporto. Questo ti darebbe una risposta a questa domanda. Basta fare in modo di fare abbastanza iterazioni che il compilatore JIT riconosce le funzioni di swap come colli di bottiglia e ottimizza i colli di bottiglia inserendo le chiamate al metodo.

Seguirò il consiglio fornito da Effective Java invece del codice in Collections.swap. Penso che tu abbia appena trovato la prova che i programmatori prendono a volte delle scorciatoie. Ciò non significa che dovresti fare lo stesso.

+1

Normalmente quando le persone dicono che l'ottimizzazione prematura è la radice di tutti i mali, stanno sostenendo che le persone scrivono un codice semplice e chiaro piuttosto che un codice complicato che secondo loro potrebbe correre più velocemente. Stai quasi discutendo il contrario.Stai dicendo che la versione contorta con due metodi è preferibile qui perché è più importante evitare i tipi grezzi piuttosto che scrivere codice semplice. Qual è il male qui? –

+0

Il malvagio sta usando una versione del codice che accede all'elenco come un tipo grezzo senza informazioni generiche. Sì, a mio parere è meglio evitare i tipi non elaborati piuttosto che scrivere codice con un numero di righe basso. Anche se il conteggio delle righe basse è importante, molte soluzioni a basso numero di linee sono abbastanza logiche. Basta vedere ad es. risposte nei puzzle di programmazione e nel sito del codice golf. Non vuoi assolutamente quelle soluzioni di conteggio delle righe basse nel tuo codice di produzione! – juhist

+0

Ho accettato la tua risposta poiché mi hai convinto che la performance non era la ragione, e sono d'accordo che probabilmente era solo l'autore a prendere una scorciatoia (specialmente perché la classe 'Collections' era già stata scritta prima dei generici). Comunque sto cominciando a pensare che ci siano delle eccezioni alla regola "mai usare i tipi grezzi". Ad esempio, non riesco a vedere che l'operatore diamond in 'List list = new ArrayList <>();' aggiunge qualsiasi cosa (a parte fare in modo che l'autore si senta a suo agio nel non utilizzare i tipi raw). Penso che evitare il metodo 'swapHelper' sia comunque un esempio migliore. –

Problemi correlati