Wie behebe ich "Der Ausdruck vom Typ Liste muss deaktiviert konvertiert werden ..."?

137

Im Java-Snippet:

SyndFeedInput fr = new SyndFeedInput();
SyndFeed sf = fr.build(new XmlReader(myInputStream));
List<SyndEntry> entries = sf.getEntries();

Die letzte Zeile generiert die Warnung

"Der Ausdruck des Typs Listmuss deaktiviert konvertiert werden, damit er übereinstimmt. List<SyndEntry>"

Was ist ein geeigneter Weg, um dies zu beheben?

user46277
quelle

Antworten:

96

Da getEntriesein Rohprodukt zurückgegeben wird List, könnte es alles halten.

Der Ansatz ohne Warnung besteht darin, ein neues List<SyndEntry>Element zu erstellen und dann jedes Element des sf.getEntries()Ergebnisses in SyndEntryumzuwandeln , bevor es Ihrer neuen Liste hinzugefügt wird. Collections.checkedListhat nicht diese Prüfung für Sie tun-obwohl es möglich gewesen wäre , es zu implementieren , dies zu tun.

Wenn Sie Ihre eigene Umwandlung im Voraus vornehmen, "halten Sie sich an die Garantiebedingungen" von Java-Generika: Wenn a ClassCastExceptionausgelöst wird, wird dies einer Umwandlung im Quellcode zugeordnet, nicht einer vom Compiler eingefügten unsichtbaren Umwandlung.

erickson
quelle
9
Vielen Dank - das ist ein interessanter Einblick in die "Garantie" und die unsichtbare Umwandlung, die der Compiler vorgenommen hat, im Vergleich zu einer Umwandlung, die explizit in meinem eigenen Code vorgenommen wurde.
user46277
1
Ja, der Wert von nicht reifizierten Generika ist etwas begrenzt, aber das ist eine Sache, die es bietet. Um dies zu verdeutlichen, muss Ihr Code ohne Sicherheitswarnungen kompiliert werden.
Erickson
Hallo erickson, ich stimme zu, dass dies in der Tat die beste Lösung ist. Überprüfen Sie meine Antwort stackoverflow.com/questions/367626/… auf eine generische Version dieser Lösung.
Bruno De Fraine
115

Dies ist ein häufiges Problem beim Umgang mit APIs vor Java 5. Um die Lösung von erickson zu automatisieren , können Sie die folgende generische Methode erstellen:

public static <T> List<T> castList(Class<? extends T> clazz, Collection<?> c) {
    List<T> r = new ArrayList<T>(c.size());
    for(Object o: c)
      r.add(clazz.cast(o));
    return r;
}

Dies ermöglicht Ihnen Folgendes:

List<SyndEntry> entries = castList(SyndEntry.class, sf.getEntries());

Da diese Lösung mittels einer Umwandlung überprüft, ob die Elemente tatsächlich den richtigen Elementtyp haben, ist sie sicher und nicht erforderlich SuppressWarnings.

Bruno De Fraine
quelle
5
In Bezug auf die von Bruno vorgeschlagene Methode: Würde dies nicht die Anwendungsleistung beeinträchtigen, wenn Listen mit vielen Elementen vorhanden sind? Java müsste jeden einzelnen von ihnen besetzen.
Will824
2
Wenn Sie Garantien wünschen, sind das die Kosten. Gibt es eine andere günstigere Option? Wenn Sie die Kontrolle über die aufgerufene Raw-Collection-Rückgabemethode haben oder sogar die Methode aufrufen oder mit einem Lazy-Demand-Ansatz auf die Collection zugreifen. Was berücksichtigt die gesamte Sammlung nach dem Methodenaufruf?
Dan
28

Es sieht so aus, SyndFeedals würden keine Generika verwendet.

Sie könnten entweder eine unsichere Besetzung und eine Warnunterdrückung haben:

@SuppressWarnings("unchecked")
List<SyndEntry> entries = (List<SyndEntry>) sf.getEntries();

oder rufen Sie Collections.checkedList auf - obwohl Sie die Warnung immer noch unterdrücken müssen:

@SuppressWarnings("unchecked")
List<SyndEntry> entries = Collections.checkedList(sf.getEntries(), SyndEntry.class);
Jon Skeet
quelle
Da beide die Warnung unterdrücken, irgendwelche Vorteile für den einen oder anderen oder eine Präferenz? Vielen Dank! Außerdem: Ist die Besetzung erforderlich, wenn die ungeprüfte Unterdrückung vorhanden ist?
Dan Rosenstark
3
@Yar: Nun, Collections.checkedListwird später das Hinzufügen von Nicht-SyndEntry-Elementen verhindern. Ich persönlich benutze nicht checkedListviel, aber dann komme ich auch nicht oft in diese ungeprüfte Besetzungssituation ...
Jon Skeet
9

Hast du das geschrieben SyndFeed?

Gibt sf.getEntriesListe zurück oder List<SyndEntry>? Ich vermute, es kehrt zurück Listund wenn Sie es in "Zurück" ändern, List<SyndEntry>wird das Problem behoben.

Wenn SyndFeedes Teil einer Bibliothek ist, können Sie die Warnung nicht entfernen, ohne die @SuppressWarning("unchecked")Annotation zu Ihrer Methode hinzuzufügen .

Alex B.
quelle
Sie können auch eine explizite Besetzung hinzufügen.
Uri
3
Eine Besetzung erzeugt nur eine weitere Warnung, da der Code nicht typsicher ist.
Erickson
SyndFeedkommt von rometools.github.io/rome/ROMEReleases/ROME1.0Release.html . Das Problem scheint in neueren Versionen von Rom behoben zu sein, wie sie unter mvnrepository.com/artifact/com.rometools/rome/1.9.0
daloonik
2

Wenn Sie Guava verwenden und nur Ihre Werte durchlaufen möchten:

for(SyndEntry entry: Iterables.filter(sf.getEntries(), SyndEntry.class){
  ...
}

Wenn Sie eine aktuelle Liste benötigen, können Sie diese verwenden

List<SyndEntry> list = Lists.newArrayList(
    Iterables.filter(sf.getEntries(), SyndEntry.class));

oder

List<SyndEntry> list = ImmutableList.copyOf(
    Iterables.filter(sf.getEntries(), SyndEntry.class));
Joseph K. Strauss
quelle
1
SyndFeedInput fr = new SyndFeedInput();
SyndFeed sf = fr.build(new XmlReader(myInputStream));
List<?> entries = sf.getEntries();
Honglonglong
quelle
2
Selbst wenn der hier bereitgestellte Code das Problem löst, möchte ich Sie ermutigen, kurz zu erklären, warum dies so ist. Bitte erläutern Sie, warum die veröffentlichte Antwort das Problem löst.
Sbrattla
1

Wenn Sie sich das Javadoc für die Klasse ansehen SyndFeed(ich nehme an, Sie beziehen sich auf die Klasse com.sun.syndication.feed.synd.SyndFeed), gibt die Methode getEntries () nicht zurück java.util.List<SyndEntry>, sondern nur java.util.List.

Dafür benötigen Sie eine explizite Besetzung.

Shyam
quelle
0

Wenn Sie nicht bei jedem Aufruf von sf.getEntries () @SuppressWarning ("nicht aktiviert") einfügen möchten, können Sie jederzeit einen Wrapper erstellen, der List zurückgibt.

Siehe diese andere Frage

Boune
quelle
0

Sogar einfacher

return new ArrayList<?>(getResultOfHibernateCallback(...))

DennisTemper
quelle
Dann würden Sie sich zur Verwendungszeit für jedes Element in ArrayList <?> Mit dem richtigen Casting (Re-Casting?) Befassen.
Ingyhere