Comment corriger "L'expression de type List nécessite une conversion non cochée…"?


137

Dans l'extrait de code Java:

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

la dernière ligne génère l'avertissement

"L'expression de type Listnécessite une conversion non vérifiée pour se conformer à List<SyndEntry>"

Quelle est la manière appropriée de résoudre ce problème?

Réponses:


96

Depuis getEntriesrenvoie un raw List, il peut contenir n'importe quoi.

L'approche sans avertissement consiste à créer un nouveau List<SyndEntry>, puis à convertir chaque élément du sf.getEntries()résultat SyndEntryavant de l'ajouter à votre nouvelle liste. Collections.checkedListne fait pas cette vérification à votre place - bien qu'il aurait été possible de l'implémenter pour le faire.

En faisant votre propre cast en amont, vous "respectez les conditions de garantie" des génériques Java: si a ClassCastExceptionest déclenché, il sera associé à un cast dans le code source, pas à un cast invisible inséré par le compilateur.


9
Merci - c'est un aperçu intéressant sur la "garantie" et la distribution invisible faite par le compilateur par rapport à une distribution faite explicitement dans mon propre code.
user46277

1
Oui, la valeur des génériques non réifiés est quelque peu limitée, mais c'est une chose qu'ils fournissent. Juste pour clarifier, cela nécessite que votre code se compile sans avertissements de sécurité de type.
erickson

Salut Erickson, je suis d'accord que c'est en effet la meilleure solution. Consultez ma réponse stackoverflow.com/questions/367626/… pour une version générique de cette solution.
Bruno De Fraine

115

C'est un problème courant lors du traitement des API pré-Java 5. Pour automatiser la solution d'erickson , vous pouvez créer la méthode générique suivante:

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

Cela vous permet de faire:

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

Parce que cette solution vérifie que les éléments ont bien le type d'élément correct au moyen d'un moulage, elle est sûre et ne nécessite pas SuppressWarnings.


5
En ce qui concerne la méthode suggérée par Bruno, cela ne nuirait-il pas aux performances de l'application en ayant des listes avec de nombreux éléments ?. Java devrait lancer chacun d'entre eux.
will824

2
Si vous voulez des garanties, c'est le coût. Existe-t-il une autre option moins chère? Évidemment, si vous avez le contrôle sur la méthode de retour de la collection brute invoquée, ou même si vous appelez la méthode ou accédez à la collection en utilisant une approche à la demande différée. Quelque chose qui considère la collection entière après l'invocation de la méthode?
dan

28

Il semble SyndFeedne pas utiliser de génériques.

Vous pouvez avoir un casting non sécurisé et une suppression d'avertissement:

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

ou appelez Collections.checkedList - bien que vous deviez toujours supprimer l'avertissement:

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

Puisqu'ils suppriment tous les deux l'avertissement, des avantages pour l'un ou l'autre, ou une préférence? Merci! Aussi: la distribution est-elle nécessaire si la suppression non contrôlée est en place?
Dan Rosenstark

3
@Yar: Eh bien, Collections.checkedListcela empêchera l'ajout d'éléments non-SyndEntry plus tard. Personnellement, je n'en utilise pas checkedListbeaucoup, mais je ne me retrouve pas non plus souvent dans cette situation de casting incontrôlée de toute façon ...
Jon Skeet

9

Avez-vous écrit le SyndFeed?

Est - sf.getEntriesretour Liste ou List<SyndEntry>? Je suppose qu'il revient Listet le changer pour revenir List<SyndEntry>résoudra le problème.

Si SyndFeedfait partie d'une bibliothèque, je ne pense pas que vous puissiez supprimer l'avertissement sans ajouter l' @SuppressWarning("unchecked")annotation à votre méthode.


Vous pouvez également ajouter une distribution explicite.
Uri

3
Un cast produira juste un autre avertissement, car le code n'est pas de type sûr.
erickson

SyndFeedprovient de rometools.github.io/rome/ROMEReleases/ROME1.0Release.html . Le problème semble être résolu dans les versions plus récentes de Rome comme celles trouvées sur mvnrepository.com/artifact/com.rometools/rome/1.9.0
daloonik

2

Si vous utilisez Guava et que tout ce que vous voulez faire est de parcourir vos valeurs:

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

Si vous avez besoin d'une liste réelle, vous pouvez utiliser

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

ou

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
Même si le code fourni ici résout le problème, je vous encourage à expliquer brièvement pourquoi il le fait. Veuillez expliquer pourquoi la réponse publiée résout le problème.
sbrattla

1

Si vous regardez le javadoc pour la classe SyndFeed(je suppose que vous faites référence à la classe com.sun.syndication.feed.synd.SyndFeed), la méthode getEntries () ne retourne pas java.util.List<SyndEntry>, mais renvoie simplementjava.util.List .

Vous avez donc besoin d'un casting explicite pour cela.


0

Si vous ne voulez pas mettre @SuppressWarning ("non coché") à chaque appel sf.getEntries (), vous pouvez toujours créer un wrapper qui renverra List.

Voir cette autre question


0

Encore plus simple

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


Ensuite, vous vous occuperiez de la conversion appropriée (re-cast?) Au moment de l'utilisation pour chaque élément dans ArrayList <?>.
ingyhere
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.