Простой способ конвертировать Iterable в коллекцию - PullRequest
378 голосов
/ 20 июня 2011

В моем приложении я использую стороннюю библиотеку (точнее Spring Data для MongoDB).

Методы этой библиотеки возвращают Iterable<T>, тогда как остальная часть моего кода ожидает Collection<T>.

Есть ли где-нибудь полезный метод, который позволит мне быстро конвертировать один в другой? Я бы не хотел создавать в своем коде кучу циклов foreach для такой простой вещи.

Ответы [ 16 ]

361 голосов
/ 21 июня 2011

С Гуавой вы можете использовать Lists.newArrayList (Iterable) или Sets.newHashSet (Iterable) , среди других подобных методов.Это, конечно, скопирует все элементы в память.Если это не приемлемо, я думаю, что ваш код, который работает с ними, должен принимать Iterable, а не Collection.Также в Гуаве предусмотрены удобные методы для действий, которые вы можете выполнять на Collection с использованием Iterable (например, Iterables.isEmpty(Iterable) или Iterables.contains(Iterable, Object)), но последствия для производительности более очевидны.

321 голосов
/ 27 мая 2015

В JDK 8, вне зависимости от дополнительных библиотек:

Iterator<T> source = ...;
List<T> target = new ArrayList<>();
source.forEachRemaining(target::add);

Редактировать: выше для Iterator.Если вы имеете дело с Iterable,

iterable.forEach(target::add);
86 голосов
/ 21 июня 2011

Вы можете написать свой собственный метод утилит для этого:

public static <E> Collection<E> makeCollection(Iterable<E> iter) {
    Collection<E> list = new ArrayList<E>();
    for (E item : iter) {
        list.add(item);
    }
    return list;
}
70 голосов
/ 02 июня 2014

Краткое решение с Java 8 с использованием java.util.stream:

public static <T> List<T> toList(final Iterable<T> iterable) {
    return StreamSupport.stream(iterable.spliterator(), false)
                        .collect(Collectors.toList());
}
45 голосов
/ 28 апреля 2013

IteratorUtils из commons-collections может помочь (хотя они не поддерживают генерики в последней стабильной версии 3.2.1):

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

Версия 4.0 (которая в данный момент находится в SNAPSHOT) поддерживает дженерики, и вы можете избавиться от @SuppressWarnings.

Обновление: проверка IterableAsList из Cactoos .

19 голосов
/ 21 июня 2011

С CollectionUtils :

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

Вот полные источники этого служебного метода:

public static <T> void addAll(Collection<T> collection, Iterator<T> iterator) {
    while (iterator.hasNext()) {
        collection.add(iterator.next());
    }
}
14 голосов
/ 19 октября 2013

Я использую FluentIterable.from(myIterable).toList() много.

14 голосов
/ 30 августа 2012

Не забывайте, что все коллекции конечны, а у Iterable нет никаких обещаний. Если что-то итерируемо, вы можете получить итератор и все.

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

будет расширен до:

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

it.hasNext () не требуется для возврата false. Таким образом, в общем случае вы не можете рассчитывать на то, что сможете конвертировать каждый Iterable в коллекцию. Например, вы можете перебирать все положительные натуральные числа, перебирать что-то с циклами, которые снова и снова выдают одинаковые результаты и т. Д.

В противном случае: ответ Атри вполне нормальный.

8 голосов
/ 18 июня 2013

Это не ответ на ваш вопрос, но я считаю, что это решение вашей проблемы. Интерфейс org.springframework.data.repository.CrudRepository действительно имеет методы, которые возвращают java.lang.Iterable, но вы не должны использовать этот интерфейс. Вместо этого используйте подчиненные интерфейсы, в вашем случае org.springframework.data.mongodb.repository.MongoRepository. Этот интерфейс имеет методы, которые возвращают объекты типа java.util.List.

7 голосов
/ 04 сентября 2014

Я использую свою пользовательскую утилиту для приведения существующей Коллекции, если она доступна.

Main:

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

В идеале вышеприведенное должно использовать 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));
}

Я реализую аналогичные утилиты для всех подтипов коллекций (Set, List и т. Д.). Я думаю, они уже будут частью Гуавы, но я не нашел ее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...