Easy way to convert Iterable to Collection

前端 未结 19 2170
忘了有多久
忘了有多久 2020-11-28 01:39

In my application I use 3rd party library (Spring Data for MongoDB to be exact).

Methods of this library return Iterable, while the rest of my

相关标签:
19条回答
  • 2020-11-28 02:21

    From CollectionUtils:

    List<T> targetCollection = new ArrayList<T>();
    CollectionUtils.addAll(targetCollection, iterable.iterator())
    

    Here are the full sources of this utility method:

    public static <T> void addAll(Collection<T> collection, Iterator<T> iterator) {
        while (iterator.hasNext()) {
            collection.add(iterator.next());
        }
    }
    
    0 讨论(0)
  • 2020-11-28 02:23

    Here's an SSCCE for a great way to do this in Java 8

    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);
        }
    }
    
    0 讨论(0)
  • 2020-11-28 02:26

    Two remarks

    1. There is no need to convert Iterable to Collection to use foreach loop - Iterable may be used in such loop directly, there is no syntactical difference, so I hardly understand why the original question was asked at all.
    2. Suggested way to convert Iterable to Collection is unsafe (the same relates to CollectionUtils) - there is no guarantee that subsequent calls to the next() method return different object instances. Moreover, this concern is not pure theoretical. E.g. Iterable implementation used to pass values to a reduce method of Hadoop Reducer always returns the same value instance, just with different field values. So if you apply makeCollection from above (or CollectionUtils.addAll(Iterator)) you will end up with a collection with all identical elements.
    0 讨论(0)
  • 2020-11-28 02:28

    While at it, do not forget that all collections are finite, while Iterable has no promises whatsoever. If something is Iterable you can get an Iterator and that is it.

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

    will be expanded to:

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

    it.hasNext() is not required to ever return false. Thus in the general case you cannot expect to be able to convert every Iterable to a Collection. For example you can iterate over all positive natural numbers, iterate over something with cycles in it that produces the same results over and over again, etc.

    Otherwise: Atrey's answer is quite fine.

    0 讨论(0)
  • 2020-11-28 02:30

    As soon as you call contains, containsAll, equals, hashCode, remove, retainAll, size or toArray, you'd have to traverse the elements anyway.

    If you're occasionally only calling methods such as isEmpty or clear I suppose you'd be better of by creating the collection lazily. You could for instance have a backing ArrayList for storing previously iterated elements.

    I don't know of any such class in any library, but it should be a fairly simple exercise to write up.

    0 讨论(0)
  • 2020-11-28 02:31

    IteratorUtils from commons-collections may help (although they don't support generics in the latest stable version 3.2.1):

    @SuppressWarnings("unchecked")
    Collection<Type> list = IteratorUtils.toList(iterable.iterator());
    

    Version 4.0 (which is in SNAPSHOT at this moment) supports generics and you can get rid of the @SuppressWarnings.

    Update: Check IterableAsList from Cactoos.

    0 讨论(0)
提交回复
热议问题