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

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

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


当前回答

如果您可以更新到Spring Data 3,那么这个问题已经解决了。有一个新的界面ListCrudRepository,它做的正是你想要的。

这是来自https://spring.io/blog/2022/02/22/announcing-listcrudrepository-friends-for-spring-data-3-0:的界面

public interface ListCrudRepository<T, ID> extends CrudRepository<T, ID> {
    <S extends T> List<S> saveAll(Iterable<S> entities);
    List<T> findAll();
    List<T> findAllById(Iterable<ID> ids);
}

注意,在版本3中必须实现两个接口

所以在版本2中

public interface PersonRepository<Person, Long> extends 
   PagingAndSortingRepository<Person, Long> {}

在版本3中应改为:

public interface PersonRepository<Person, Long> extends
    PagingAndSortingRepository<Person, Long>,ListCrudRepository<Person, Long> {}

其他变化见https://spring.io/blog/2022/02/22/announcing-listcrudrepository-friends-for-spring-data-3-0

其他回答

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

我使用我的自定义实用程序强制转换现有的集合(如果可用)。

主要:

public static <T> Collection<T> toCollection(Iterable<T> iterable) {
    if (iterable instanceof Collection) {
        return (Collection<T>) iterable;
    } else {
        return Lists.newArrayList(iterable);
    }
}

理想情况下,上面将使用immutabelist,但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));
}

我为集合的所有子类型(Set,List等)实现了类似的实用程序。我以为这些已经是番石榴的一部分了,但我还没找到。

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

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

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

我在试图获取项目列表时遇到了类似的情况,而不是在CrudRepository接口中声明的默认Iterable<T> findAll()。因此,在我的ProjectRepository接口(从CrudRepository扩展而来)中,我简单地声明了findAll()方法来返回一个List<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();
}

我认为这是最简单的解决方案,不需要转换逻辑或使用外部库。

您可以使用Eclipse Collections工厂:

Iterable<String> iterable = Arrays.asList("1", "2", "3");

MutableList<String> list = Lists.mutable.withAll(iterable);
MutableSet<String> set = Sets.mutable.withAll(iterable);
MutableSortedSet<String> sortedSet = SortedSets.mutable.withAll(iterable);
MutableBag<String> bag = Bags.mutable.withAll(iterable);
MutableSortedBag<String> sortedBag = SortedBags.mutable.withAll(iterable);

您还可以将Iterable转换为LazyIterable,并使用转换器方法或任何其他可用的api。

Iterable<String> iterable = Arrays.asList("1", "2", "3");
LazyIterable<String> lazy = LazyIterate.adapt(iterable);

MutableList<String> list = lazy.toList();
MutableSet<String> set = lazy.toSet();
MutableSortedSet<String> sortedSet = lazy.toSortedSet();
MutableBag<String> bag = lazy.toBag();
MutableSortedBag<String> sortedBag = lazy.toSortedBag();

以上所有可变类型都扩展了java.util.Collection。

注意:我是Eclipse Collections的提交者。