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?

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.


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.


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);

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 .


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));

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

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.


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


0

Sogar einfacher

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


Dann würden Sie sich zur Verwendungszeit für jedes Element in ArrayList <?> Mit dem richtigen Casting (Re-Casting?) Befassen.
— Ingyhere
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.