Collections.emptyList() gibt eine Liste zurück?

Lesezeit: 4 Minuten

Benutzer-Avatar
Chris Conway

Ich habe einige Probleme beim Navigieren in der Java-Regel zum Ableiten von generischen Typparametern. Betrachten Sie die folgende Klasse, die einen optionalen Listenparameter hat:

import java.util.Collections;
import java.util.List;

public class Person {
  private String name;
  private List<String> nicknames;
  
  public Person(String name) {
    this(name, Collections.emptyList());
  }
  
  public Person(String name, List<String> nicknames) {
    this.name = name;
    this.nicknames = nicknames;
  }
}

Mein Java-Compiler gibt folgenden Fehler aus:

Person.java:9: The constructor Person(String, List<Object>) is undefined

Aber Collections.emptyList() gibt den Typ zurück <T> List<T>nicht List<Object>. Das Hinzufügen einer Besetzung hilft nicht

public Person(String name) {
  this(name,(List<String>)Collections.emptyList());
}

Erträge

Person.java:9: inconvertible types

Verwenden EMPTY_LIST Anstatt von emptyList()

public Person(String name) {
  this(name, Collections.EMPTY_LIST);
}

Erträge

Person.java:9: warning: [unchecked] unchecked conversion

Während die folgende Änderung den Fehler verschwinden lässt:

public Person(String name) {
  this.name = name;
  this.nicknames = Collections.emptyList();
}

Kann jemand erklären, gegen welche Typprüfungsregel ich hier stoße und wie ich sie am besten umgehen kann? In diesem Beispiel ist das letzte Codebeispiel zufriedenstellend, aber bei größeren Klassen möchte ich in der Lage sein, Methoden zu schreiben, die diesem „optionalen Parameter“-Muster folgen, ohne Code zu duplizieren.

Für zusätzliches Guthaben: wann ist es angebracht, es zu verwenden EMPTY_LIST im Gegensatz zu emptyList()?

  • Für alle Fragen zu Java-Generika empfehle ich “Java-Generika und -Sammlungen“ von Maurice Naftalin, Philip Wadler.

    – Julien Chastang

    20. November 2008 um 20:39 Uhr

Das Problem, auf das Sie stoßen, ist, dass obwohl die Methode emptyList() kehrt zurück List<T>Sie haben es nicht mit dem Typ versehen, daher wird es standardmäßig zurückgegeben List<Object>. Sie können den Typparameter angeben und Ihren Code so wie erwartet verhalten:

public Person(String name) {
  this(name,Collections.<String>emptyList());
}

Wenn Sie jetzt eine direkte Zuweisung vornehmen, kann der Compiler die generischen Typparameter für Sie ermitteln. Das nennt man Typinferenz. Wenn Sie beispielsweise Folgendes getan haben:

public Person(String name) {
  List<String> emptyList = Collections.emptyList();
  this(name, emptyList);
}

dann ist die emptyList() Aufruf würde a korrekt zurückgeben List<String>.

  • Ich habs. Da ich aus der ML-Welt komme, finde ich es seltsam, dass Java nicht auf den richtigen Typ schließen kann: Der Typ des formalen Parameters und der Rückgabetyp von emptyList sind eindeutig unifizierbar. Aber ich denke, der Typinferenzer kann nur “Babyschritte” machen.

    – Chris Conway

    20. November 2008 um 20:43 Uhr

  • In einigen einfachen Fällen mag es dem Compiler möglich erscheinen, in diesem Fall auf den fehlenden Typparameter zu schließen – aber das könnte gefährlich sein. Wenn mehrere Versionen der Methode mit unterschiedlichen Parametern vorhanden waren, könnten Sie am Ende die falsche aufrufen. Und der zweite existiert vielleicht noch gar nicht…

    – Bill Michel

    25. November 2008 um 13:47 Uhr

  • Diese Notation “Collections.emptyList()” ist wirklich seltsam, aber sinnvoll. Einfacher als Enum>. 🙂

    – Thiago Chaves

    23. Juni 2009 um 17:07 Uhr

  • Die Bereitstellung eines Typparameters ist in Java 8 nicht mehr erforderlich (es sei denn, es gibt eine Mehrdeutigkeit bei möglichen generischen Typen).

    – Vitalii Fedorenko

    6. April 2014 um 20:10 Uhr

  • Das zweite Snippet zeigt den Typrückschluss gut, lässt sich aber natürlich nicht kompilieren. Der Aufruf an this muss die erste Anweisung im Konstruktor sein.

    – Arjan

    10. Juli 2016 um 2:30 Uhr

Benutzer-Avatar
Auto

Sie möchten verwenden:

Collections.<String>emptyList();

Wenn Sie sich die Quelle für die leere Liste ansehen, sehen Sie, dass sie eigentlich nur a tut

return (List<T>)EMPTY_LIST;

  • einwandfreie Antwort @carson

    – Gaurav

    9. März um 12:59 Uhr

Die Methode emptyList hat diese Signatur:

public static final <T> List<T> emptyList()

Dass <T> vor dem Wort Liste bedeutet, dass der Wert des generischen Parameters T aus dem Variablentyp abgeleitet wird, dem das Ergebnis zugewiesen ist. Also in diesem Fall:

List<String> stringList = Collections.emptyList();

Der Rückgabewert wird dann explizit durch eine Variable vom Typ referenziert List<String>, damit der Compiler es herausfinden kann. In diesem Fall:

setList(Collections.emptyList());

Es gibt keine explizite Rückgabevariable, die der Compiler verwenden kann, um den generischen Typ herauszufinden, daher ist dies standardmäßig der Fall Object.

Benutzer-Avatar
Lii

Seit Java 8 wird diese Art von Code wie erwartet kompiliert und der Typparameter wird vom Compiler abgeleitet.

public Person(String name) {
    this(name, Collections.emptyList()); // Inferred to List<String> in Java 8
}

public Person(String name, List<String> nicknames) {
    this.name = name;
    this.nicknames = nicknames;
}

Das Neue an Java 8 ist, dass die Zieltyp eines Ausdrucks wird verwendet, um Typparameter seiner Unterausdrücke abzuleiten. Vor Java 8 wurden nur direkte Zuweisungen und Argumente an Methoden für die Inferenz von Typparametern verwendet.

In diesem Fall ist der Parametertyp des Konstruktors der Zieltyp für Collections.emptyList()und der Rückgabewerttyp wird passend zum Parametertyp ausgewählt.

Dieser Mechanismus wurde in Java 8 hauptsächlich hinzugefügt, um Lambda-Ausdrücke kompilieren zu können, aber er verbessert Typrückschlüsse im Allgemeinen.

Java nähert sich dem Richtigen Hindley-Milner Typrückschluss bei jeder Veröffentlichung!

1358410cookie-checkCollections.emptyList() gibt eine Liste zurück?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy