2010-09-17 6 views
38

Stavo guardando il numero ImmutableList di Guava e ho notato che il metodo of() è stato sovraccaricato 12 volte.Perché ImmutableList di Guava ha così tanti metodi overload()?

Mi sembra che tutto quello che serviva era:

static <E> ImmutableList<E> of(); 
static <E> ImmutableList<E> of(E element); // not even necessary 
static <E> ImmutableList<E> of(E... elements); 

Qual è la ragione per avere così tante varianti simili?

+5

E tutti passano comunque i loro parametri a un metodo varargs interno ... eh. Dovrò alzare un sopracciglio a questo. Hmm, la fonte ha un commento "Arrivano fino a undici. Dopo di ciò, ottieni il modulo varargs e gli eventuali avvertimenti potrebbero venire con esso. :(". Non sono sicuro di quali avvertimenti si riferisca a, comunque. –

+0

@Tim, questo probabilmente farebbe una buona risposta, vale la pena almeno e upvote, e probabilmente la risposta accettata – jjnguy

+7

+1 per Google per arrivare fino a undici! – romacafe

risposta

39

Varargs e generici non suonano bene insieme. I metodi varargs possono causare un avviso con argomenti generici e gli overload impediscono tale avviso tranne nel raro caso in cui si vogliano aggiungere più di 11 voci all'elenco immutable usando of().

I commenti nell'origine dicono:

questi vanno fino a undici. Dopodiché, ottieni il modulo varargs e gli eventuali avvisi potrebbero arrivare. :(

Nota che Java 7 di @SafeVarargs annotazione è stato aggiunto appositamente per eliminare la necessità di questo genere di cose. Un singolo metodo of(E...) annotato con @SafeVarargs potrebbe essere utilizzato e non darebbe gli avvisi con gli argomenti generici.

+0

Ehi, Potresti aggiornare la tua risposta in modo che rifletta la parte relativa alle prestazioni a cui fa riferimento @Rinke? Penso che sia degno di nota. –

+2

@ JoãoRebelo: Questo in realtà non è vero però ... i metodi vanno immediatamente e chiamano un metodo varargs. – ColinD

+0

Intendi in questo caso specifico? O sto fraintendendo cosa intendevi? –

13

Esiste anche un motivo per le prestazioni: ogni richiamo di un metodo varargs causa un'allocazione e un'inizializzazione dell'array. Se in qualche modo è stato determinato che, ad esempio, il 95% delle chiamate ha 3 o meno argomenti e solo il 5% con 4 o più, quindi sovraccarico come questo

public static <E> ImmutableList<E> of(); 
public static <E> ImmutableList<E> of(E e); 
public static <E> ImmutableList<E> of(E e1, E e2); 
public static <E> ImmutableList<E> of(E e1, E e2, E e3); 
public static <E> ImmutableList<E> of(E e1, E e2, E e3, E... es); 

porta ad un buon incremento delle prestazioni nel 95% dei casi. Diversamente, la performance media del caso sale.

+6

Nota: Sebbene il principio sia valido, ho appena saputo da ColinD che in realtà non è vero per Guava perché i metodi sovraccaricati comportano comunque una chiamata varargs (nell'attuale implementazione). – Rinke

4

Oltre alle altre grandi risposte qui, c'è un sottile vantaggio in termini di prestazioni in runtime (oltre a evitare l'allocazione dell'array), ovvero che gli overload di zero-arg e single-arg restituiscono implementazioni ottimizzate per rappresentare vuoti e liste di istanze singole (rispettivamente).

Se non avessimo sovraccarichi metodo separate per questi e comprendevano solo un singolo metodo varargs-based, quindi questo metodo sarebbe simile a questa:

public static <E> ImmutableList<E> of(E... es) { 
    switch (es.length) { 
     case 0: 
     return emptyImmutableList(); 
     case 1: 
     return singletonImmutableList(es[0]); 
     default: 
     return defaultImmutableList(es); 
    } 
} 

La performance del caso interruttore (o se -else checks) non sarebbe male per la maggior parte delle chiamate, ma non è ancora necessario poiché può solo avere overload di metodi per ogni ottimizzazione, e il compilatore sa sempre quale sovraccarico chiamare. Non c'è nessun peso sul codice cliente, quindi è una vittoria facile.