Як виправити "Вираз 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.