Java Easy way to convert Iterable to Collection

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6416706/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 05:45:35  来源:igfitidea点击:

Easy way to convert Iterable to Collection

javacollections

提问by Ula Krukar

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

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

Methods of this library return Iterable<T>, while the rest of my code expects Collection<T>.

Methods of this library return Iterable<T>, while the rest of my code expects Collection<T>.

Is there any utility method somewhere that will let me quickly convert one to the other? I would like to avoid creating a bunch of foreachloops in my code for such a simple thing.

Is there any utility method somewhere that will let me quickly convert one to the other? I would like to avoid creating a bunch of foreachloops in my code for such a simple thing.

采纳答案by ColinD

With Guavayou can use Lists.newArrayList(Iterable)or Sets.newHashSet(Iterable), among other similar methods. This will of course copy all the elements in to memory. If that isn't acceptable, I think your code that works with these ought to take Iterablerather than Collection. Guava also happens to provide convenient methods for doing things you can do on a Collectionusing an Iterable(such as Iterables.isEmpty(Iterable)or Iterables.contains(Iterable, Object)), but the performance implications are more obvious.

With Guavayou can use Lists.newArrayList(Iterable)or Sets.newHashSet(Iterable), among other similar methods. This will of course copy all the elements in to memory. If that isn't acceptable, I think your code that works with these ought to take Iterablerather than Collection. Guava also happens to provide convenient methods for doing things you can do on a Collectionusing an Iterable(such as Iterables.isEmpty(Iterable)or Iterables.contains(Iterable, Object)), but the performance implications are more obvious.

回答by aioobe

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

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

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

If you're occasionally only calling methods such as isEmptyor clearI suppose you'd be better of by creating the collection lazily. You could for instance have a backing ArrayListfor 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.

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

回答by Tomasz Nurkiewicz

From CollectionUtils:

From CollectionUtils:

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

Here are the full sources of this utility method:

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());
    }
}

回答by Atreys

You may write your own utility method for this as well:

You may write your own utility method for this as well:

public static <E> Collection<E> makeCollection(Iterable<E> iter) {
    Collection<E> list = new ArrayList<E>();
    for (E item : iter) {
        list.add(item);
    }
    return list;
}

回答by Alexander Shopov

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.

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:

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.

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.

Otherwise: Atrey's answer is quite fine.

回答by al0

Two remarks

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.
  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.

回答by yegor256

IteratorUtilsfrom commons-collectionsmay help (although they don't support generics in the latest stable version 3.2.1):

IteratorUtilsfrom commons-collectionsmay 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.

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

Update: Check IterableAsListfrom Cactoos.

Update: Check IterableAsListfrom Cactoos.

回答by Ludwig Magnusson

This is not an answer to your question but I believe it is the solution to your problem. The interface org.springframework.data.repository.CrudRepositorydoes indeed have methods that return java.lang.Iterablebut you should not use this interface. Instead use sub interfaces, in your case org.springframework.data.mongodb.repository.MongoRepository. This interface has methods that return objects of type java.util.List.

This is not an answer to your question but I believe it is the solution to your problem. The interface org.springframework.data.repository.CrudRepositorydoes indeed have methods that return java.lang.Iterablebut you should not use this interface. Instead use sub interfaces, in your case org.springframework.data.mongodb.repository.MongoRepository. This interface has methods that return objects of type java.util.List.

回答by fringd

I use FluentIterable.from(myIterable).toList()a lot.

I use FluentIterable.from(myIterable).toList()a lot.

回答by fringd

In Java 8 you can do this to add all elements from an Iterableto Collectionand return it:

In Java 8 you can do this to add all elements from an Iterableto Collectionand return it:

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

Inspired by @Afreys answer.

Inspired by @Afreys answer.