在我的应用程序中,我使用第三方库(Spring Data for MongoDB准确地说)。
这个库的方法返回Iterable<T>,而我的其余代码期望Collection<T>。
有没有什么实用的方法可以让我快速地把一个转换成另一个?为了这么简单的事情,我希望避免在代码中创建一堆foreach循环。
在我的应用程序中,我使用第三方库(Spring Data for MongoDB准确地说)。
这个库的方法返回Iterable<T>,而我的其余代码期望Collection<T>。
有没有什么实用的方法可以让我快速地把一个转换成另一个?为了这么简单的事情,我希望避免在代码中创建一堆foreach循环。
当前回答
在JDK 8+中,不使用任何额外的库:
Iterator<T> source = ...;
List<T> target = new ArrayList<>();
source.forEachRemaining(target::add);
编辑:上面的是迭代器。如果你在处理Iterable,
iterable.forEach(target::add);
其他回答
试试Cactoos的StickyList:
List<String> list = new StickyList<>(iterable);
你也可以编写自己的实用方法:
public static <E> Collection<E> makeCollection(Iterable<E> iter) {
Collection<E> list = new ArrayList<E>();
for (E item : iter) {
list.add(item);
}
return list;
}
如果您可以更新到Spring Data 3,那么这个问题已经解决了。有一个新的界面ListCrudRepository,它做的正是你想要的。
这是来自https://spring.io/blog/2022/02/22/announcing-listcrudrepository-friends-for-spring-data-3-0:的界面
public interface ListCrudRepository<T, ID> extends CrudRepository<T, ID> {
<S extends T> List<S> saveAll(Iterable<S> entities);
List<T> findAll();
List<T> findAllById(Iterable<ID> ids);
}
注意,在版本3中必须实现两个接口
所以在版本2中
public interface PersonRepository<Person, Long> extends
PagingAndSortingRepository<Person, Long> {}
在版本3中应改为:
public interface PersonRepository<Person, Long> extends
PagingAndSortingRepository<Person, Long>,ListCrudRepository<Person, Long> {}
其他变化见https://spring.io/blog/2022/02/22/announcing-listcrudrepository-friends-for-spring-data-3-0
您可以使用Eclipse Collections工厂:
Iterable<String> iterable = Arrays.asList("1", "2", "3");
MutableList<String> list = Lists.mutable.withAll(iterable);
MutableSet<String> set = Sets.mutable.withAll(iterable);
MutableSortedSet<String> sortedSet = SortedSets.mutable.withAll(iterable);
MutableBag<String> bag = Bags.mutable.withAll(iterable);
MutableSortedBag<String> sortedBag = SortedBags.mutable.withAll(iterable);
您还可以将Iterable转换为LazyIterable,并使用转换器方法或任何其他可用的api。
Iterable<String> iterable = Arrays.asList("1", "2", "3");
LazyIterable<String> lazy = LazyIterate.adapt(iterable);
MutableList<String> list = lazy.toList();
MutableSet<String> set = lazy.toSet();
MutableSortedSet<String> sortedSet = lazy.toSortedSet();
MutableBag<String> bag = lazy.toBag();
MutableSortedBag<String> sortedBag = lazy.toSortedBag();
以上所有可变类型都扩展了java.util.Collection。
注意:我是Eclipse Collections的提交者。
当你从Spring Data中获得你的Iterable时,你有两个额外的选择。
You can override the method that returns the Iterable in the repository with a version that returns a List, Set or Streamable. This way Spring Data is doing the conversion for you. You may do so in a super interface of your repositories so you don't have to repeat the override in all your repository interfaces. If you happen to use Spring Data JPA this is already done for you in JpaRepository You may do the conversion using the just mentioned Streamable yourself: Iterable<X> iterable = repo.findAll(); List<X> list = Streamable.of(iterable).toList();
既然你提到了沮丧,也许还有一些决定使用Iterable帮助的背景。
It is expected that it is actually fairly rare to actually require a Collection so in many cases it shouldn't make a difference. Using the overriding mechanics one can return different types which wouldn't be possible with a more specific return type like Collection. This would make it impossible to return a Streamable which is intended for cases where a store may decide to return a result before all elements have been fetched. Streamable would actually be a flexible return type, since it offers easy conversions to List, Set, Stream and is itself an Iterable. But this would require you to use a Spring Data specific type in your application which many users wouldn't like.
在参考文档中有关于这方面的章节。