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?

utilisateur46277
la source

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.

Erickson
la source
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.

Bruno De Fraine
la source
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);
Jon Skeet
la source
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.

Alex B
la source
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));
Joseph K. Strauss
la source
1
SyndFeedInput fr = new SyndFeedInput();
SyndFeed sf = fr.build(new XmlReader(myInputStream));
List<?> entries = sf.getEntries();
Honglonglong
la source
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.

Shyam
la source
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

Boune
la source
0

Encore plus simple

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

DennisTemper
la source
Ensuite, vous vous occuperiez de la conversion appropriée (re-cast?) Au moment de l'utilisation pour chaque élément dans ArrayList <?>.
ingyhere