在我的应用程序中,我使用第三方库(Spring Data for MongoDB准确地说)。
这个库的方法返回Iterable<T>,而我的其余代码期望Collection<T>。
有没有什么实用的方法可以让我快速地把一个转换成另一个?为了这么简单的事情,我希望避免在代码中创建一堆foreach循环。
在我的应用程序中,我使用第三方库(Spring Data for MongoDB准确地说)。
这个库的方法返回Iterable<T>,而我的其余代码期望Collection<T>。
有没有什么实用的方法可以让我快速地把一个转换成另一个?为了这么简单的事情,我希望避免在代码中创建一堆foreach循环。
当前回答
从CollectionUtils:
List<T> targetCollection = new ArrayList<T>();
CollectionUtils.addAll(targetCollection, iterable.iterator())
下面是这个实用方法的完整源代码:
public static <T> void addAll(Collection<T> collection, Iterator<T> iterator) {
while (iterator.hasNext()) {
collection.add(iterator.next());
}
}
其他回答
这不是对你问题的回答,但我相信这是解决你问题的办法。org.springframework.data.repository.CrudRepository接口确实有返回java.lang.Iterable的方法,但是你不应该使用这个接口。而是使用子接口,在你的例子中是org.springframework.data.mongodb.repository.MongoRepository。该接口具有返回java.util.List类型对象的方法。
当你从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.
在参考文档中有关于这方面的章节。
有点晚了,但我创建了一个非常优雅的Java 8解决方案,允许将T的Iterable转换为T的任何集合,而不需要任何库:
public static <T, C extends Collection<T>> C toCollection(Iterable<T> iterable, Supplier<C> baseSupplier)
{
C collection = baseSupplier.get();
iterable.forEach(collection::add);
return collection;
}
使用的例子:
Iterable<String> iterable = ...;
List<String> list = toCollection(iterable, ArrayList::new);
下面是一个在Java 8中实现这一功能的SSCCE
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class IterableToCollection {
public interface CollectionFactory <T, U extends Collection<T>> {
U createCollection();
}
public static <T, U extends Collection<T>> U collect(Iterable<T> iterable, CollectionFactory<T, U> factory) {
U collection = factory.createCollection();
iterable.forEach(collection::add);
return collection;
}
public static void main(String[] args) {
Iterable<Integer> iterable = IntStream.range(0, 5).boxed().collect(Collectors.toList());
ArrayList<Integer> arrayList = collect(iterable, ArrayList::new);
HashSet<Integer> hashSet = collect(iterable, HashSet::new);
LinkedList<Integer> linkedList = collect(iterable, LinkedList::new);
}
}
在JDK 8+中,不使用任何额外的库:
Iterator<T> source = ...;
List<T> target = new ArrayList<>();
source.forEachRemaining(target::add);
编辑:上面的是迭代器。如果你在处理Iterable,
iterable.forEach(target::add);