在我的应用程序中,我使用第三方库(Spring Data for MongoDB准确地说)。

这个库的方法返回Iterable<T>,而我的其余代码期望Collection<T>。

有没有什么实用的方法可以让我快速地把一个转换成另一个?为了这么简单的事情,我希望避免在代码中创建一堆foreach循环。


当前回答

下面是一个在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);
    }
}

其他回答

当你从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.

在参考文档中有关于这方面的章节。

这不是对你问题的回答,但我相信这是解决你问题的办法。org.springframework.data.repository.CrudRepository接口确实有返回java.lang.Iterable的方法,但是你不应该使用这个接口。而是使用子接口,在你的例子中是org.springframework.data.mongodb.repository.MongoRepository。该接口具有返回java.util.List类型对象的方法。

在Java 8中,你可以这样做,将Iterable中的所有元素添加到Collection中并返回:

public static <T> Collection<T> iterableToCollection(Iterable<T> iterable) {
  Collection<T> collection = new ArrayList<>();
  iterable.forEach(collection::add);
  return collection;
}

灵感来自@Afreys的回答。

因为RxJava是一个锤子,而这个看起来像钉子,你可以这样做

Observable.from(iterable).toList().toBlocking().single();

试试Cactoos的StickyList:

List<String> list = new StickyList<>(iterable);