Як виправити "Вираз List List потребує неперевіреної конверсії ..."?


137

У фрагменті Java:

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

останній рядок генерує попередження

"Вираз типу Listпотребує неперевіреного перетворення, щоб відповідати List<SyndEntry>"

Який спосіб це виправити?

Відповіді:


96

Оскільки getEntriesповертає сировину List, вона може вмістити все, що завгодно.

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

Роблячи свій власний лицьовий фронт, ви "дотримуєтесь гарантійних умов" дженериків Java: якщо a ClassCastExceptionбуде піднято, він буде пов'язаний з анонсом у вихідному коді, а не невидимим складом, вставленим компілятором.


9
Дякую - це цікаве розуміння "гарантії" та невидимого амплітуди, зробленого компілятором, аніж кастинг, зроблений явно в моєму власному коді.
— user46277

1
Так, цінність нереалізованих дженериків дещо обмежена, але це є одне, що вона дає. Щоб уточнити, це вимагає, щоб ваш код компілювався без попереджень про безпеку типу.
— erickson

Привіт, Еріксон, я згоден, що це дійсно найкраще рішення. Перевірте мою відповідь 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.ckedList - хоча все-таки потрібно буде придушити попередження:

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

Оскільки вони обидва придушують попередження, будь-які переваги тому чи іншому чи перевагу? Дякую! Також: чи потрібний склад, якщо встановлено безперебійне придушення?
— Дан Розенстарк

3
@Yar: Добре, Collections.checkedListзаважатиме додавати будь-які не-SyndEntry елементи пізніше. Особисто я мало використовую checkedList, але все одно я часто не потрапляю в цю неперевірену ситуацію в ролях ...
— Джон Скіт

9

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

Чи sf.getEntriesповертається Список чи List<SyndEntry>? Моя здогадка, це повернення Listта зміна його на повернення List<SyndEntry>вирішить проблему.

Якщо SyndFeedце частина бібліотеки, я не думаю, що ви можете видалити попередження без додавання @SuppressWarning("unchecked")примітки до свого методу.


Ви також можете додати чіткий склад.
— Урі

3
Лист просто видасть ще одне попередження, оскільки код не є безпечним.
— erickson

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

2
Навіть якщо наданий тут код вирішує проблему, я б радив вам коротко пояснити, чому це робиться. Поясніть, будь ласка, чому розміщена відповідь вирішує проблему.
— сбраттла

1

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

Тож для цього вам потрібен чіткий склад.


0

Якщо ви не хочете ставити @SuppressWarning ("невірно") на кожен виклик sf.getEntries (), ви завжди можете зробити обгортку, яка поверне Список.

Дивіться це інше питання


0

Ще простіше

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


Тоді ви будете мати справу з правильним кастингом (повторним кастингом?) Під час використання кожного елемента в ArrayList <?>.
— ingyhere
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.