【发布时间】:2015-12-10 19:02:11
【问题描述】:
我有一个难题让我思考是否有任何标准的 java 类实现了Iterable<T> 而没有实现Collection<T>。我正在实现一个接口,该接口需要我定义一个接受Iterable<T> 的方法,但我用来支持此方法的对象需要Collection<T>。
这让我做了一些非常笨拙的代码,在编译时会给出一些未经检查的警告。
public ImmutableMap<Integer, Optional<Site>> loadAll(
Iterable<? extends Integer> keys
) throws Exception {
Collection<Integer> _keys;
if (keys instanceof Collection) {
_keys = (Collection<Integer>) keys;
} else {
_keys = Lists.newArrayList(keys);
}
final List<Site> sitesById = siteDBDao.getSitesById(_keys);
// snip: convert the list to a map
将生成的集合更改为使用更通用的 Collection<? extends Integer> 类型并不能消除该行的未经检查的警告。此外,我无法将方法签名更改为接受Collection 而不是Iterable,因为这样它就不再覆盖超级方法并且在需要时不会被调用。
doesn't seem to be a way around 这个转换或复制问题:这里和其他地方已经提出了其他问题,它似乎深深植根于 Java 的泛型和类型擦除系统。但我要问的是,是否有任何类可以实现Iterable<T>,但也不能实现Collection<T>?我查看了Iterable JavaDoc,当然我希望传递给我的界面的所有内容实际上都是一个集合。我想改用一个狂野的、预先编写的类,因为这似乎更有可能实际作为参数传递,并使单元测试更有价值。
由于我正在编写一些单元测试,我确定我编写的强制转换或复制位适用于我在项目中使用它的类型。但我想为是一个可迭代但不是一个集合的一些输入编写一个单元测试,到目前为止我所能想到的正在自己实现一个虚拟测试类实现。
出于好奇,我正在实现的方法是 Guava 的 CacheLoader<K, V>.loadAll(Iterable<? extends K> keys),支持方法是 JDBI 实例化的数据访问对象,它需要一个集合用作 @BindIn 接口的参数类型。我认为我认为这与问题相切是正确的,但以防万一有人想尝试横向思考我的问题。我知道我可以只分叉 JDBI 项目并重写 @BindIn 注释以接受可迭代...
【问题讨论】:
-
回答标题中的问题:例如是
ServiceLoader。 -
复制有什么问题——也就是制作一个新的收藏?您只会复制引用,而不是创建新对象。
-
没什么大错,但我一直在寻找一种方法来避免进行任何分配。顾名思义,
Lists.newArrayList可以分配一个新数组,可能是log(n)次,因为它在分配后备数组之前没有获得大小。 (虽然再看番石榴代码,才发现自己的instanceof then cast是多余的。) -
请注意,调用者在调用此方法后仍然可以更新
keys。如果这打破了您的假设,那么在所有情况下都可能需要一份副本。
标签: java generics collections iterable