Ula*_*kar 398 java collections
在我的应用程序中,我使用第三方库(确切地说是MongoDB的Spring Data).
这个库的方法返回Iterable<T>,而我的其余代码需要Collection<T>.
有什么实用方法可以让我快速将一个转换为另一个吗?我想避免foreach在我的代码中为这么简单的事情创建一堆循环.
Col*_*inD 373
使用Guava,您可以使用Lists.newArrayList(Iterable)或Sets.newHashSet(Iterable)以及其他类似的方法.这当然会将所有元素复制到内存中.如果这是不可接受的,我认为你的代码应该采用Iterable而不是Collection.Guava也恰好提供了方便的方法来处理你可以在Collection使用Iterable(例如Iterables.isEmpty(Iterable)或Iterables.contains(Iterable, Object))上做的事情,但性能影响更明显.
Tha*_*wda 341
在JDK 8中,不依赖于其他库:
Iterator<T> source = ...;
List<T> target = new ArrayList<>();
source.forEachRemaining(target::add);
Run Code Online (Sandbox Code Playgroud)
编辑:以上是为了Iterator.如果你正在处理Iterable,
iterable.forEach(target::add);
Run Code Online (Sandbox Code Playgroud)
Atr*_*eys 89
您也可以为此编写自己的实用程序方法:
public static <E> Collection<E> makeCollection(Iterable<E> iter) {
Collection<E> list = new ArrayList<E>();
for (E item : iter) {
list.add(item);
}
return list;
}
Run Code Online (Sandbox Code Playgroud)
xeh*_*puk 75
使用Java 8的简明解决方案java.util.stream:
public static <T> List<T> toList(final Iterable<T> iterable) {
return StreamSupport.stream(iterable.spliterator(), false)
.collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)
yeg*_*256 48
IteratorUtils从commons-collections可能会有帮助(尽管他们不支持最新的稳定版本3.2.1中的泛型):
@SuppressWarnings("unchecked")
Collection<Type> list = IteratorUtils.toList(iterable.iterator());
Run Code Online (Sandbox Code Playgroud)
版本4.0(此时在SNAPSHOT中)支持泛型,你可以摆脱它@SuppressWarnings.
更新:IterableAsList从Cactoos检查.
Tom*_*icz 20
List<T> targetCollection = new ArrayList<T>();
CollectionUtils.addAll(targetCollection, iterable.iterator())
Run Code Online (Sandbox Code Playgroud)
以下是此实用程序方法的完整来源:
public static <T> void addAll(Collection<T> collection, Iterator<T> iterator) {
while (iterator.hasNext()) {
collection.add(iterator.next());
}
}
Run Code Online (Sandbox Code Playgroud)
小智 14
在此期间,不要忘记所有集合都是有限的,而Iterable没有任何承诺.如果某些东西是Iterable,你可以得到一个Iterator,就是这样.
for (piece : sthIterable){
..........
}
Run Code Online (Sandbox Code Playgroud)
将扩大到:
Iterator it = sthIterable.iterator();
while (it.hasNext()){
piece = it.next();
..........
}
Run Code Online (Sandbox Code Playgroud)
it.hasNext()不需要返回false.因此,在一般情况下,您不能指望能够将每个Iterable转换为Collection.例如,你可以迭代所有正数自然数,迭代一些带有循环的东西,一遍又一遍地产生相同的结果,等等.
否则:Atrey的答案很好.
Man*_*iri 12
我碰到过类似的情况来试图获取一个List的ProjectS,而不是默认Iterable<T> findAll()的声明CrudRepository接口。因此,在我的ProjectRepository接口(从 扩展CrudRepository)中,我只是声明了findAll()返回 aList<Project>而不是 的方法Iterable<Project>。
package com.example.projectmanagement.dao;
import com.example.projectmanagement.entities.Project;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
public interface ProjectRepository extends CrudRepository<Project, Long> {
@Override
List<Project> findAll();
}
Run Code Online (Sandbox Code Playgroud)
我认为这是最简单的解决方案,不需要转换逻辑或使用外部库。
Jen*_*der 12
当您Iterable从 Spring Data获取时,您有几个额外的选择。
您可以Iterable使用返回List,Set或的版本覆盖在存储库中返回 的方法Streamable。这样,Spring Data 就会为您进行转换。
您可以在存储库的超级界面中执行此操作,因此您不必在所有存储库界面中重复覆盖。
如果您碰巧使用 Spring Data JPA,这已经为您完成 JpaRepository
您可以使用刚才提到的Streamable自己进行转换:
Iterable<X> iterable = repo.findAll();
List<X> list = Streamable.of(iterable).toList();
Run Code Online (Sandbox Code Playgroud)
既然你提到心烦意乱,也许还有一些决定使用Iterable帮助的背景。
Collection情况实际上相当罕见,因此在许多情况下它不应该有所作为。Collection. 这将使得无法返回 a Streamable,它适用于商店可能决定在获取所有元素之前返回结果的情况。Streamable实际上是一个灵活的返回类型,因为它提供了到List, 的简单转换Set,Stream并且它本身就是一个Iterable. 但这将要求您在应用程序中使用许多用户不喜欢的 Spring Data 特定类型。这不是您问题的答案,但我相信这是您问题的解决方案.该接口org.springframework.data.repository.CrudRepository确实具有返回的方法,java.lang.Iterable但您不应使用此接口.而是使用子接口,在您的情况下org.springframework.data.mongodb.repository.MongoRepository.此接口具有返回类型对象的方法java.util.List.
我使用自定义实用程序来转换现有的Collection(如果可用).
主要:
public static <T> Collection<T> toCollection(Iterable<T> iterable) {
if (iterable instanceof Collection) {
return (Collection<T>) iterable;
} else {
return Lists.newArrayList(iterable);
}
}
Run Code Online (Sandbox Code Playgroud)
理想情况下,上面将使用ImmutableList,但ImmutableCollection不允许可能提供不良结果的空值.
测试:
@Test
public void testToCollectionAlreadyCollection() {
ArrayList<String> list = Lists.newArrayList(FIRST, MIDDLE, LAST);
assertSame("no need to change, just cast", list, toCollection(list));
}
@Test
public void testIterableToCollection() {
final ArrayList<String> expected = Lists.newArrayList(FIRST, null, MIDDLE, LAST);
Collection<String> collection = toCollection(new Iterable<String>() {
@Override
public Iterator<String> iterator() {
return expected.iterator();
}
});
assertNotSame("a new list must have been created", expected, collection);
assertTrue(expected + " != " + collection, CollectionUtils.isEqualCollection(expected, collection));
}
Run Code Online (Sandbox Code Playgroud)
我为集合的所有子类型(Set,List等)实现了类似的实用程序.我认为这些已经成为番石榴的一部分,但我还没有找到它.
只要你打电话contains,containsAll,equals,hashCode,remove,retainAll,size或者toArray,你无论如何都要穿越元素.
如果你偶尔只调用这样的方法,isEmpty或者clear我认为通过懒惰创建集合你会更好.例如,您可以支持ArrayList存储以前迭代的元素.
我不知道任何图书馆里有这样的课程,但写起来应该是一个相当简单的练习.
小智 5
在Java 8,你可以做到这一点从一个添加的所有元素Iterable来Collection并返回它:
public static <T> Collection<T> iterableToCollection(Iterable<T> iterable) {
Collection<T> collection = new ArrayList<>();
iterable.forEach(collection::add);
return collection;
}
Run Code Online (Sandbox Code Playgroud)
受到@Afreys答案的启发。
由于RxJava是一把锤子,看起来有点像钉子,所以您可以
Observable.from(iterable).toList().toBlocking().single();
Run Code Online (Sandbox Code Playgroud)