如何修复“列表类型的表达式需要未经检查的转换...”?


137

在Java代码段中:

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

最后一行生成警告

“类型的表达式List需要未经检查的转换才能符合List<SyndEntry>

解决此问题的合适方法是什么?

Answers:


96

由于getEntries返回原始List,因此可以容纳任何内容。

无警告的方法是创建一个new List<SyndEntry>,然后将sf.getEntries()结果的每个元素强制转换为,然后再将其SyndEntry添加到新列表中。Collections.checkedList没有做这个检查你-虽然它本来可以实现它这样做。

通过ClassCastException预先进行自己的转换,您将“遵守Java泛型的保修条款”:如果将a 引发,它将与源代码中的转换相关联,而不是与编译器插入的不可见转换相关联。


9
谢谢-这是关于“保修”和编译器进行的无形转换与我自己的代码中显式进行的转换的有趣见解。
user46277

1
是的,未修饰的泛型的价值受到一定限制,但这确实是一件事。需要澄清的是,这要求您的代码在编译时没有类型安全警告。
erickson

嗨,埃里克森,我同意这确实是最好的解决方案。检查我的答案stackoverflow.com/questions/367626/…,以获得该解决方案的通用版本。
布鲁诺·德·弗赖恩

115

在处理Java 5之前的API时,这是一个常见问题。要使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
关于Bruno建议的方法,当List包含很多元素时,这是否会损害应用程序的性能?Java将不得不强制转换每个。
will824 2011年

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

由于它们都抑制了警告,因此对彼此的好处还是偏好?谢谢!另外:如果未选中抑制功能,是否需要强制转换?
Dan Rosenstark 2014年

3
@Yar:好吧,Collections.checkedList稍后将阻止添加任何非SyndEntry元素。我个人并没有使用checkedList太多,但是无论如何我也很少遇到这种不受限制的情况……
Jon Skeet 2014年

9

你写了SyndFeed吗?

是否sf.getEntries返回List或List<SyndEntry>?我的猜测是返回List,将其更改为return List<SyndEntry>将解决此问题。

如果SyndFeed是库的一部分,我认为您可以在不向@SuppressWarning("unchecked")方法中添加注释的情况下删除警告。


您还可以添加显式强制转换。
Uri

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
即使这里提供的代码解决了问题,我还是鼓励您简要解释一下为什么这样做。请解释为什么发布的答案可以解决问题。
sbrattla'5

1

如果您查看该类的javadoc SyndFeed(我想您是指该类com.sun.syndication.feed.synd.SyndFeed),则getEntries()方法不会返回java.util.List<SyndEntry>,而只会返回java.util.List

因此,您需要为此进行显式转换。


0

如果您不想在每个sf.getEntries()调用上放置@SuppressWarning(“ unchecked”),则始终可以创建一个将返回List的包装器。

看到另一个问题


0

更容易

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


然后,您将在使用时对ArrayList <?>中的每个元素进行适当的转换(重新铸造?)。
ingyhere
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.