Как мне исправить «Выражение типа List нуждается в непроверенном преобразовании…»?

137

Во фрагменте Java:

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

последняя строка генерирует предупреждение

«Выражение типа Listнуждается в непроверенном преобразовании, чтобы соответствовать List<SyndEntry>»

Как правильно это исправить?

user46277
источник

Ответы:

96

Так как getEntriesвозвращает raw List, он может содержать что угодно.

Подход без предупреждения заключается в создании нового List<SyndEntry>, а затем приведении каждого элемента sf.getEntries()результата к нему SyndEntryперед добавлением его в новый список. Collections.checkedListэто не сделать эту проверку для вас, хотя это было бы возможно осуществить это сделать это.

Выполняя собственное преобразование, вы «соблюдаете условия гарантии» обобщений Java: если значение a ClassCastExceptionповышено, оно будет связано с приведением в исходном коде, а не с невидимым приведением, вставленным компилятором.

Эриксон
источник
9
Спасибо - это интересное понимание "гарантии" и невидимого преобразования, выполненного компилятором, по сравнению с приведением явно в моем собственном коде.
user46277 16.12.08
1
Да, ценность непроизведенных дженериков несколько ограничена, но это одна вещь, которую она обеспечивает. Просто чтобы уточнить, это требует, чтобы ваш код компилировался без предупреждений о безопасности типов.
Эриксон
Привет Эриксон, я согласен, что это действительно лучшее решение. Проверьте мой ответ stackoverflow.com/questions/367626/… для общей версии этого решения.
Бруно Де Фрейн
115

Это распространенная проблема при работе с API до Java 5. Чтобы автоматизировать решение от erickson , вы можете создать следующий общий метод:

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

Это позволяет вам делать:

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

Поскольку это решение проверяет, что элементы действительно имеют правильный тип элемента с помощью приведения, оно безопасно и не требует SuppressWarnings.

Бруно Де Фрейн
источник
5
Что касается метода, предложенного Бруно, не повредит ли это производительности приложения при наличии списков со многими элементами? Ява должна была бы разыграть каждого из них.
will824
2
Если вы хотите гарантий, это стоимость. Есть ли другой, менее дорогой вариант? Очевидно, что если у вас есть контроль над вызванным методом возврата необработанной коллекции, или даже вызов метода или доступ к коллекции с использованием подхода с отложенным запросом. Что-нибудь, что рассматривает всю коллекцию после вызова метода?
дан
28

Похоже, SyndFeedне использует дженерики.

Вы могли бы иметь небезопасное приведение и подавление предупреждения:

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

или вызовите Collections.checkedList - хотя вам все равно нужно подавить предупреждение:

@SuppressWarnings("unchecked")
List<SyndEntry> entries = Collections.checkedList(sf.getEntries(), SyndEntry.class);
Джон Скит
источник
Так как они оба подавляют предупреждение, какие-либо преимущества для одного или другого, или предпочтения? Спасибо! Кроме того: необходим ли бросок, если есть неконтролируемое подавление?
Дэн Розенстарк
3
@ Яр: Хорошо, Collections.checkedListпозже мы предотвратим добавление элементов, не относящихся к SyndEntry. Лично я мало пользуюсь checkedList, но в любом случае я тоже не часто попадаю в эту непроверенную ситуацию с актерами ...
Джон Скит
9

Вы написали SyndFeed?

sf.getEntriesВозвращает ли список или List<SyndEntry>? Я предполагаю, что он возвращается, Listи изменение его на возврат List<SyndEntry>решит проблему.

Если SyndFeedэто часть библиотеки, я не думаю, что вы можете удалить предупреждение, не добавляя @SuppressWarning("unchecked")аннотацию к вашему методу.

Алекс Б
источник
Вы также можете добавить явное приведение.
Ури
3
Приведение просто выдаст другое предупреждение, так как код не является безопасным типом.
Эриксон
SyndFeedвзято из rometools.github.io/rome/ROMEReleases/ROME1.0Release.html . Эта проблема, похоже, решена в более поздних версиях Рима, таких как те, которые можно найти на mvnrepository.com/artifact/com.rometools/rome/1.9.0
daloonik
2

Если вы используете Guava и все, что вы хотите сделать, это перебрать ваши значения:

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

Если вам нужен актуальный список, вы можете использовать

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

или

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();
Honglonglong
источник
2
Даже если приведенный здесь код решает проблему, я бы посоветовал вам кратко объяснить, почему это происходит. Пожалуйста, объясните, почему опубликованный ответ решает проблему.
Сбраттла
1

Если вы посмотрите на javadoc для класса SyndFeed(я полагаю, вы ссылаетесь на класс com.sun.syndication.feed.synd.SyndFeed), метод getEntries () не возвращает java.util.List<SyndEntry>, а возвращает просто java.util.List.

Таким образом, вам нужно явное приведение для этого.

Shyam
источник
0

Если вы не хотите помещать @SuppressWarning ("unchecked") в каждый вызов sf.getEntries (), вы всегда можете создать оболочку, которая будет возвращать List.

Смотрите этот другой вопрос

Boune
источник
0

Еще проще

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

DennisTemper
источник
Тогда вы будете иметь дело с правильным приведением (повторным приведением?) Во время использования для каждого элемента в ArrayList <?>.
ingyhere