Collections.emptyList () vs. nuova istanza


241

In pratica, è meglio restituire un elenco vuoto come questo :

return Collections.emptyList();

O come questo :

return new ArrayList<Foo>();

O dipende completamente da cosa hai intenzione di fare con l'elenco restituito?

Risposte:


300

La differenza principale è che Collections.emptyList()restituisce un elenco immutabile , ovvero un elenco a cui non è possibile aggiungere elementi. (Lo stesso vale per l' List.of()introduzione in Java 9.)

Nei rari casi in cui si fa desidera modificare la lista restituita, Collections.emptyList()e List.of()sono quindi non una buona scelta.

Direi che la restituzione di un elenco immutabile va benissimo (e persino nel modo preferito) purché il contratto (documentazione) non sia esplicitamente indicato diversamente.


Inoltre, emptyList() potrebbe non creare un nuovo oggetto con ogni chiamata.

Le implementazioni di questo metodo non devono creare un oggetto Elenco separato per ogni chiamata. L'uso di questo metodo avrà probabilmente costi comparabili rispetto all'utilizzo del campo con nomi simili. (A differenza di questo metodo, il campo non fornisce la sicurezza del tipo.)

L'implementazione di emptyListsembra come segue:

public static final <T> List<T> emptyList() {
    return (List<T>) EMPTY_LIST;
}

Quindi, se il tuo metodo (che restituisce un elenco vuoto) viene chiamato molto spesso, questo approccio potrebbe persino darti prestazioni leggermente migliori sia per la CPU che per la memoria.


4
Quindi, sarebbe Collections.emptyList()più adatto per dire, controllo degli errori e simili?
martedì

1
I client API non riceveranno NullPointerExceptionrestituendo Collections.emptyList()anziché null.
realPK,

@PK_J fa un punto importante. Collections.emptyList()è iterabile e restituisce una lunghezza, quindi può essere utilizzato per i loop senza che venga generata un'eccezione.
ndm13,

che ne dici di usare List.of()?

4
@AJW, sì. Ma rispetto a, diciamo, new ArrayList<>()rende anche chiara la decisione di progettazione; gli elementi non verranno aggiunti a questo elenco.
aioobe,

51

A partire da Java 5.0 è possibile specificare il tipo di elemento nel contenitore:

Collections.<Foo>emptyList()

Concordo con le altre risposte che per i casi in cui si desidera restituire un elenco vuoto che rimane vuoto, è necessario utilizzare questo approccio.


38
A partire da Java 7, puoi fare in modo che il compilatore deduca il parametro type dell'invocazione del metodo generico dal tipo target:List<Foo> list = Collections.emptyList()
Paul Jackson,

28

Collections.emptyList è immutabile, quindi esiste una differenza tra le due versioni, quindi è necessario considerare gli utenti del valore restituito.

Il ritorno new ArrayList<Foo>crea sempre una nuova istanza dell'oggetto in modo che abbia un leggero costo aggiuntivo associato che potrebbe darti un motivo per usarlo Collections.emptyList. Mi piace usare emptyListsolo perché è più leggibile.


14

Stai attento però. Se ritorni Collections.emptyList()e poi provi a fare alcune modifiche con esso add()o smth in quel modo, avrai un UnsupportedOperationException()perché Collections.emptyList()restituisce un oggetto immutabile.


7

Vorrei andare con Collections.emptyList() se l'elenco restituito non viene modificato in alcun modo (poiché l'elenco è immutabile), altrimenti andrei con l'opzione 2.

Il vantaggio Collections.emptyList()è che la stessa istanza statica viene restituita ogni volta e quindi non si verifica la creazione dell'istanza per ogni chiamata.


3

Utilizzare Collections.emptyList () se si desidera assicurarsi che l'elenco restituito non venga mai modificato. Questo è ciò che viene restituito quando si chiama emptyList ():

/**
 * The empty list (immutable). 
 */
public static final List EMPTY_LIST = new EmptyList();

Sono arrivato qui cercando di scoprire se chiamare Collections.emptyList()aveva un costo di costruzione. Vedere i dettagli dell'implementazione (anche se probabilmente non è lo stesso su tutte le JVM) lo conferma. @Atul, da quale JVM proviene?
wjl,

2

Le risposte fornite sottolineano il fatto che emptyList()restituisce un valore immutabile Listma non danno alternative. I ArrayList(int initialCapacity)casi speciali del costruttore , 0quindi tornare al new ArrayList<>(0)posto di new ArrayList<>()potrebbe anche essere una soluzione praticabile:

/**
 * Shared empty array instance used for empty instances.
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

[...]

/**
 * Constructs an empty list with the specified initial capacity.
 *
 * @param  initialCapacity  the initial capacity of the list
 * @throws IllegalArgumentException if the specified initial capacity
 *         is negative
 */
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

(fonti da Java 1.8.0_72)


Non sono d'accordo con il tuo approccio. Si risparmia un po 'di memoria e CPU sull'inizializzazione, ma se l'elenco restituito viene mai modificato, si perde quel tempo quando l'elenco rialloca un nuovo array. Se molti elementi vengono aggiunti all'elenco nel tempo, ciò potrebbe accumularsi in un collo di bottiglia delle prestazioni a causa del tasso di crescita molto più lento . Preferisco di gran lunga attenermi alla convenzione di un elenco vuoto non modificabile o di un elenco utilizzabile e modificabile.
Patrick M,

1
Come ho cercato di sottolineare con la mia formulazione ( potrebbe essere praticabile ): tutto dipende dal tuo caso d'uso. Sono in genere sia di ritorno mutabili o Collections unmutable, non una miscela seconda wether sono vuote oppure no. E per contrastare la "richiesta molto più lenta": questa è l'implementazione attuale.
René,

Oh amico, guardami citando le versioni principali di JDK 2 non aggiornate. Quindi java8 evita del tutto il collo di bottiglia saltando alla capacità predefinita da una dimensione iniziale di 0. Mi dispiace di essermi sbagliata.
Patrick M,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.