Collections.emptyList () vs. neue Instanz

241

In der Praxis ist es besser , eine leere Liste wie zurückzukehren dies :

return Collections.emptyList();

Oder so :

return new ArrayList<Foo>();

Oder hängt dies vollständig davon ab, was Sie mit der zurückgegebenen Liste tun werden?

mre
quelle

Antworten:

300

Der Hauptunterschied besteht darin, dass Collections.emptyList()eine unveränderliche Liste zurückgegeben wird, dh eine Liste, zu der Sie keine Elemente hinzufügen können. (Gleiches gilt für das List.of()in Java 9 eingeführte.)

In den seltenen Fällen , in denen Sie tun wollen , die zurückgegebene Liste ändern, Collections.emptyList()und List.of()sind somit nicht eine gute Wahl.

Ich würde sagen, dass die Rückgabe einer unveränderlichen Liste vollkommen in Ordnung ist (und sogar der bevorzugte Weg), solange der Vertrag (die Dokumentation) nicht ausdrücklich etwas anderes angibt.


Außerdem wird emptyList() möglicherweise nicht bei jedem Aufruf ein neues Objekt erstellt.

Implementierungen dieser Methode müssen nicht für jeden Aufruf ein separates Listenobjekt erstellen. Die Verwendung dieser Methode hat wahrscheinlich vergleichbare Kosten wie die Verwendung des gleichnamigen Felds. (Im Gegensatz zu dieser Methode bietet das Feld keine Typensicherheit.)

Die Implementierung emptyListsieht wie folgt aus:

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

Wenn Ihre Methode (die eine leere Liste zurückgibt) sehr oft aufgerufen wird, bietet dieser Ansatz möglicherweise sogar eine etwas bessere Leistung sowohl in Bezug auf die CPU als auch in Bezug auf den Speicher.

aioobe
quelle
4
Wäre es Collections.emptyList()also besser geeignet für beispielsweise Fehlerprüfungen und dergleichen?
mre
1
API-Clients erhalten nicht NullPointerExceptiondurch Zurückkehren Collections.emptyList()statt null.
RealPK
@PK_J macht einen wichtigen Punkt. Collections.emptyList()ist iterierbar und gibt eine Länge zurück, sodass es für for-Schleifen verwendet werden kann, ohne dass eine Ausnahme ausgelöst wird.
ndm13
was ist mit verwenden List.of()?
4
@ Ajw, ja. Aber im Vergleich zu beispielsweise new ArrayList<>()macht es auch die Entwurfsentscheidung klar; Elemente werden dieser Liste nicht hinzugefügt.
Aioobe
51

Ab Java 5.0 können Sie den Elementtyp im Container angeben:

Collections.<Foo>emptyList()

Ich stimme den anderen Antworten zu, dass Sie in Fällen, in denen Sie eine leere Liste zurückgeben möchten, die leer bleibt, diesen Ansatz verwenden sollten.

Paul Jackson
quelle
38
Ab Java 7 können Sie den Compiler den Typparameter des generischen Methodenaufrufs aus dem Zieltyp ableiten lassen:List<Foo> list = Collections.emptyList()
Paul Jackson
28

Collections.emptyList ist unveränderlich, daher gibt es einen Unterschied zwischen den beiden Versionen, sodass Sie Benutzer des zurückgegebenen Werts berücksichtigen müssen.

Durch die Rückgabe wird new ArrayList<Foo>immer eine neue Instanz des Objekts erstellt, sodass nur sehr geringe zusätzliche Kosten anfallen, die Ihnen möglicherweise einen Grund für die Verwendung geben Collections.emptyList. Ich benutze emptyListes gerne, nur weil es besser lesbar ist.

Jeff Foster
quelle
14

Sei aber vorsichtig. Wenn Sie zurückkehren Collections.emptyList()und dann versuchen, einige Änderungen daran add()oder so vorzunehmen, haben Sie ein UnsupportedOperationException()Weil, Collections.emptyList()das ein unveränderliches Objekt zurückgibt.

Sergey Frolov
quelle
7

Ich würde mit gehen, Collections.emptyList()wenn die zurückgegebene Liste in keiner Weise geändert wird (da die Liste unveränderlich ist), sonst würde ich mit Option 2 gehen.

Der Vorteil von Collections.emptyList()ist, dass jedes Mal dieselbe statische Instanz zurückgegeben wird und daher nicht für jeden Aufruf eine Instanz erstellt wird.

S73417H
quelle
3

Verwenden Sie Collections.emptyList (), wenn Sie sicherstellen möchten, dass die zurückgegebene Liste niemals geändert wird. Dies wird beim Aufruf von emptyList () zurückgegeben:

/**
 * The empty list (immutable). 
 */
public static final List EMPTY_LIST = new EmptyList();
Atul
quelle
Ich kam hier an, um herauszufinden, ob ein Anruf Collections.emptyList()Baukosten hatte. Das Anzeigen der Implementierungsdetails (obwohl wahrscheinlich nicht bei allen JVMs gleich) bestätigt, dass dies nicht der Fall ist. @Atul, von welcher JVM ist das?
wjl
2

Die gegebenen Antworten betonen die Tatsache, dass emptyList()eine unveränderliche zurückgegeben wird List, geben aber keine Alternativen. Die Konstruktor- ArrayList(int initialCapacity)Sonderfälle 0, bei denen new ArrayList<>(0)statt zurückgegeben wird, new ArrayList<>()könnten ebenfalls eine praktikable Lösung sein:

/**
 * 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);
    }
}

(Quellen aus Java 1.8.0_72)

René
quelle
Ich bin mit Ihrem Ansatz nicht einverstanden. Sie sparen bei der Initialisierung etwas Speicher und CPU, aber wenn die von Ihnen zurückgegebene Liste jemals geändert wird, verlieren Sie diese Zeit, wenn die Liste ein neues Array neu zuweist. Wenn der Liste im Laufe der Zeit viele Elemente hinzugefügt werden, kann dies aufgrund der viel langsameren Wachstumsrate zu einem größeren Leistungsengpass führen . Ich halte mich viel lieber an die Konvention einer nicht modifizierbaren leeren Liste oder einer verwendbaren, modifizierbaren Liste.
Patrick M
1
Als ich versuchte, mit meinem Wortlaut zu betonen ( könnte machbar sein ): Es hängt alles von Ihrem Anwendungsfall ab. Ich würde im Allgemeinen entweder veränderliche oder unveränderliche Sammlungen zurückgeben, keine Mischung, je nachdem, ob sie leer sind oder nicht. Und um der "viel langsameren Behauptung" entgegenzuwirken: Dies ist die aktuelle Implementierung.
René
Oh Mann, schau mich an und zitiere JDK 2 Hauptversionen veraltet. Java8 vermeidet den Engpass vollständig, indem es von einer anfänglichen Größe von 0 auf die Standardkapazität hochspringt. Entschuldigung, ich habe mich so geirrt.
Patrick M