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

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

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


当前回答

在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的回答。

其他回答

Java 8使用Java .util.stream的简洁解决方案:

public static <T> List<T> toList(final Iterable<T> iterable) {
    return StreamSupport.stream(iterable.spliterator(), false)
                        .collect(Collectors.toList());
}

从Java 16开始,你可以使用Stream.toList():

public static <T> List<T> toList(final Iterable<T> iterable) {
    return StreamSupport.stream(iterable.spliterator(), false)
                        .toList();
}

有点晚了,但我创建了一个非常优雅的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);

只要你调用contains, containsAll, equals, hashCode, remove, retainAll, size或toArray,你就必须遍历元素。

如果您偶尔只调用isEmpty或clear等方法,我认为您最好是惰性地创建集合。例如,你可以有一个支持数组列表来存储先前迭代的元素。

我不知道任何一个库中有这样的类,但是编写它应该是一个相当简单的练习。

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

尽管如此,不要忘记所有的集合都是有限的,而Iterable没有任何承诺。如果某个东西是Iterable,你可以得到一个Iterator,就是这样。

for (piece : sthIterable){
..........
}

将扩大到:

Iterator it = sthIterable.iterator();
while (it.hasNext()){
    piece = it.next();
..........
}

it.hasNext()不需要返回false。因此,在一般情况下,您不能期望能够将每个Iterable转换为一个集合。例如,你可以遍历所有正自然数,遍历带有循环的东西,反复产生相同的结果,等等。

除此之外:Atrey的回答很好。