Iterable을 Collection으로 변환하는 쉬운 방법


424

내 응용 프로그램에서 타사 라이브러리 (MongoDB의 스프링 데이터가 정확함)를 사용합니다.

이 라이브러리의 메소드는 반환 Iterable<T>하지만 나머지 코드는 예상 Collection<T>합니다.

어딘가에 빠르게 변환 할 수있는 유틸리티 방법이 있습니까? foreach그런 간단한 일을 위해 코드에 많은 루프를 만드는 것을 피하고 싶습니다 .


3
어쨌든 작업을 수행하는 utiliy 방법은 컬렉션을 반복해야하므로 성능 향상을 기대할 수 없습니다. 그러나 당신이 구문 설탕을 찾고 있다면 Guava 또는 Apache Collections를 갈 것입니다.
Sebastian Ganslandt 2016 년

" 어쨌든 컬렉션을 반복해야합니다. ", 아닙니다. 자세한 내용은 내 답변을 참조하십시오.
aioobe

3
특정 유스 케이스에서 Iterable <T> 대신 Collection <T> / List <T> / Set <T> (필요한 경우)를 리턴하는 메소드를 사용하여 CrudRepository를 자체 인터페이스로 확장 할 수 있습니다.
Kevin Van Dyck

답변:


387

함께 구아바 당신이 사용할 수있는 Lists.newArrayList (의 Iterable) 또는 Sets.newHashSet (의 Iterable를) 다른 유사한 방법들. 이것은 물론 모든 요소를 ​​메모리에 복사합니다. 그것이 받아 들일 수 없다면, 이것들과 작동하는 코드는 Iterable오히려 사용해야한다고 생각합니다 Collection. 구아바는 또한 당신이 할 수있는 일을하는 편리한 방법을 제공하는 일이 Collection를 사용하여 Iterable(예 : Iterables.isEmpty(Iterable)또는 Iterables.contains(Iterable, Object)),하지만 성능에 영향이 더 분명하다.


1
모든 요소를 ​​직접 반복합니까? 즉, Lists.newArrayList(Iterable).clear()선형 또는 일정 시간 작동입니까?
aioobe

2
@ aioobe : iterable의 사본을 만듭니다. 보기가 바람직하다고 지정되지 않았으며, 대부분의 메소드를 Collection보기 위해 구현할 수 없거나 Iterable비효율적이라는 점을 감안할 때 나에게 그렇게하는 것이 의미가 없습니다.
ColinD 2016 년

@ColinD보기를 원하면 어떻게해야합니까? 실제로 원하는 것은 소스 컬렉션을 다른 요소로 추가 한 결과 인 컬렉션 뷰입니다. 사용할 수는 Iterables.concat()있지만 : Iterablea가 아닌 을 제공합니다 . Collection(
Hendy Irawan

1
이것은 내 질문입니다 : stackoverflow.com/questions/4896662/… . 불행히도 문제를 해결하지 못하는 간단한 대답은을 사용하는 것 Iterables.concat()입니다. 훨씬 더 긴 대답은 Collection... 왜 이것이 더 일반적으로 지원되지 않는지 궁금합니다.
Hendy Irawan

365

추가 라이브러리를 사용하지 않고 JDK 8 이상에서 :

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

편집 : 위의 내용은입니다 Iterator. 당신이 다루고있는 경우 Iterable,

iterable.forEach(target::add);

86
또는iterable.forEach(target::add);
Cephalopod

92

이것에 대한 고유 한 유틸리티 메소드를 작성할 수도 있습니다.

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

33
1에서가는 경우 Iterable에하는 것이 Collection유일한 문제는, 내가 큰 제 3 자 컬렉션 라이브러리를 가져 오는 동안이 방법을 선호하는 것입니다.
aioobe

2
함수 코드의 4 %는 99 %가 사용되지 않는 2MB의 컴파일 된 라이브러리 코드보다 훨씬 선호됩니다. 라이센싱 복잡성이라는 또 다른 비용이 있습니다. Apache 2.0 라이센스는 유연하지만 지루한 명령이 없습니다. 이상적으로는 이러한 공통 패턴 중 일부 가 Java 런타임 라이브러리에 직접 통합 된 것을 볼 수 있습니다.
Jonathan Neufeld

2
어쨌든 ArrayList를 사용하고 있기 때문에 공변량 목록 유형을 대신 사용하는 것이 어떻습니까? 이를 통해 다운 캐스팅 또는 재구성없이 더 많은 계약을 충족시킬 수 있으며 Java는 어쨌든 하위 유형 경계를 지원하지 않습니다.
Jonathan Neufeld

@JonathanNeufeld 또는 왜 그냥 ArrayList <T>를 반환하지 않습니까?
Juan Juan

5
@Juan 그것은 SOLID 가 아니기 때문입니다 . ArrayList는 단일 책임 및 종속성 반전 원칙을 위반하는 YAGNI (아마도 불필요) 구현 세부 사항을 노출합니다. 완전히 SOLID를 유지하면서 Collection보다 조금 더 노출하기 때문에 List에 남겨 두겠습니다. INVOKEVIRTUAL보다 opcode INVOKEINTERFACE의 JVM 성능 영향에 대해 걱정이된다면 많은 벤치 마크에서 수면을 잃을 가치가 없다는 것을 알 수 있습니다.
Jonathan Neufeld

80

다음을 사용하는 Java 8을 사용한 간결한 솔루션 java.util.stream:

public static <T> List<T> toList(final Iterable<T> iterable) {
    return StreamSupport.stream(iterable.spliterator(), false)
                        .collect(Collectors.toList());
}

1
이 방법은 너무 느린과 비교 IteratorUtils에서commons-collections
알렉스 Burdusel

3
얼마나 느려? IteratorUtils.toList()Java 5 이전 방식으로 반복자를 사용하여 새로 작성된 목록에 요소를 하나씩 추가합니다. 간단하고 아마도 가장 빠르지 만 바이너리에 734 kB를 추가 하고이 방법이 가장 좋은 것으로 밝혀지면 스스로 할 수 있습니다.
xehpuk

8
때로는 첫 번째가 더 빠르며 때로는 두 번째가 더 빠르다는 결론을 내린 기본 벤치 마크를 수행했습니다. 벤치 마크를 보여주세요.
xehpuk

이 prob는 새로운 허용되는 답변이 될 수 있습니다. (구아바와 같은) 과도한 라이브러리를 피하는 것이 좋습니다.
java-addict301

48

IteratorUtilsfrom commons-collectionsmay help (최신 안정 버전 3.2.1에서는 제네릭을 지원하지 않지만) :

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

버전 4.0 (현재 SNAPSHOT에 있음)은 제네릭을 지원하며 @SuppressWarnings .

업데이트 : CactoosIterableAsList 에서 확인하십시오 .


5
그러나 그것은 Iterable이 아닌 Iterator가 필요합니다
hithwen

5
@hithwen, 나는 그것을 얻지 못합니다-Iterable은 Iterator를 제공합니다 (답변에 자세히 설명되어 있음)-무엇이 문제입니까?
Tom

내가 무슨 생각을했는지 모르겠다 ^^ U
hithwen

2
4.1부터는 IterableUtils.toList(Iterable)편리한 방법이며 IteratorUtils후드에서 사용되지만 null 안전합니다 (와 달리 IteratorUtils.toList).
Yoory N.

21

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

모든 요소를 ​​직접 반복합니까? 즉, Lists.newArrayList(someIterable).clear()선형 또는 일정 시간 작동입니까?
aioobe

addAll이름에서 알 수 있듯이 소스 코드를 추가 하여 반복자 값을 하나씩 복사합니다. 보기가 아닌 사본을 작성합니다.
Tomasz Nurkiewicz

CollectionUtils여분의 라인에서 컬렉션 생성을 건너 뛸 수있는 방법이 없다는 것이 얼마나 유감입니다 .
Karl Richter

Broken Link ☝️☝️
Hola Soy Edu Feliz Navidad

14

Iterable은 약속이 없지만 모든 컬렉션은 유한하다는 것을 잊지 마십시오. Iterable이 있으면 Iterator를 얻을 수 있습니다.

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

다음으로 확장됩니다 :

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

it.hasNext ()는 false를 반환하지 않아도됩니다. 따라서 일반적인 경우 모든 Iterable을 Collection으로 변환 할 수는 없습니다. 예를 들어, 모든 양수의 자연수를 반복하고,주기가 같은 것을 반복하여 동일한 결과를 반복해서 반복 할 수 있습니다.

그렇지 않으면 : Atrey의 대답은 꽤 좋습니다.


1
실제로 / 실제 코드에서 무한한 것을 반복하는 Iterable을 실제로 본 사람이 있습니까? 나는 그런 Iterable이 많은 곳에서 고통과 고통을 일으킬 것이라고 생각할 것이다 ... :)
David

2
@David 프로덕션 코드에서 무한 반복자를 구체적으로 지적 할 수는 없지만 발생할 수있는 경우를 생각할 수 있습니다. 비디오 게임에는 위의 답변에서 제안하는 주기적 패턴으로 항목을 만드는 기술이있을 수 있습니다. 무한 반복자가 발생하지 않았지만 메모리가 중요한 관심사 인 반복자가 발생했습니다. 디스크의 파일에 대해 반복자가 있습니다. 전체 1TB 디스크와 4GB 램이 있으면 반복기를 Collection으로 변환하는 메모리가 부족할 수 있습니다.
radicaledward101

14

FluentIterable.from(myIterable).toList()많이 사용 합니다.


9
구아바 출신이기도합니다.
Vadzim

또는 org.apache.commons.collections4에서. 그 다음의 FluentIterable.of (myIterable) .toList은 ()
뒤 - 그것은

9

이것은 귀하의 질문에 대한 답변이 아니지만 귀하의 문제에 대한 해결책이라고 생각합니다. 인터페이스 org.springframework.data.repository.CrudRepository에는 실제로 반환되는 메서드가 java.lang.Iterable있지만이 인터페이스를 사용해서는 안됩니다. 대신 귀하의 경우 하위 인터페이스를 사용하십시오 org.springframework.data.mongodb.repository.MongoRepository. 이 인터페이스에는 유형의 객체를 반환하는 메서드가 java.util.List있습니다.


2
코드를 구체적인 구현에 바인딩하지 않도록 일반 CrudRepository를 사용하는 것이 좋습니다.
stanlick

7

가능한 경우 사용자 지정 유틸리티를 사용하여 기존 컬렉션을 전송합니다.

본관:

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

이상적으로는 위의 ImmutableList를 사용하지만 ImmutableCollection은 null을 허용하지 않아 원하지 않는 결과를 제공 할 수 있습니다.

테스트 :

@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 등)에 대해 유사한 유틸리티를 구현합니다. 나는 이것이 이미 구아바의 일부라고 생각하지만 찾지 못했습니다.


1
당신의 오래된 답변은 새로운 질문 stackoverflow.com/questions/32570534/… 의 기초입니다 .
Paul Boddington

6

즉시 전화로 contains, containsAll, equals, hashCode, remove, retainAll, size또는toArray , 당신은 어쨌든 요소를 통과해야 할 것이다.

가끔과 같은 메소드를 호출 isEmpty하거나 clear컬렉션을 느리게 만드는 것이 더 낫다고 생각합니다. 예를 들어 백업을 할 수 있습니다ArrayList 이전에 반복 된 요소를 저장하기 있습니다.

나는 어떤 도서관에서 그런 클래스를 알지 못하지만 작성하는 것은 매우 간단한 연습이어야합니다.



6

자바 8에서는 당신은 모든 요소를 추가하려면이 작업을 수행 할 수 있습니다 IterableCollection그것을 반환 :

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

@Afreys의 답변에서 영감을 얻었습니다.


5

RxJava는 망치이기 때문에 손톱처럼 보이기 때문에 할 수 있습니다

Observable.from(iterable).toList().toBlocking().single();

23
jquery를 참여시킬 수있는 방법이 있습니까?
Dmitry Minkovsky

3
RxJava에 null 항목이 있으면 충돌합니다. 그렇지 않습니까?
MBH

RxJava2는 null 항목을 허용하지 않는다고 생각합니다. RxJava에서는 괜찮습니다.
DariusL

4

Java 8 에서이 작업을 수행하는 좋은 방법에 대한 SSCCE가 있습니다.

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

2

비고

  1. foreach 루프를 사용하기 위해 Iterable을 Collection으로 변환 할 필요가 없습니다 .Iterable은 그러한 루프에서 직접 사용될 수 있으므로 구문상의 차이가 없으므로 원래 질문이 왜 요청되었는지 전혀 이해하지 못합니다.
  2. Iterable을 Collection으로 변환하는 권장 방법은 안전하지 않습니다 (CollectionUtils와 동일). next () 메서드에 대한 후속 호출이 다른 객체 인스턴스를 반환한다고 보장 할 수 없습니다. 게다가이 문제는 이론적으로 순수한 것은 아닙니다. 예를 들어 Hadoop Reducer의 reduce 메소드에 값을 전달하는 데 사용되는 반복 가능한 구현은 다른 필드 값과 함께 항상 동일한 값 인스턴스를 리턴합니다. 따라서 위에서 makeCollection (또는 CollectionUtils.addAll (Iterator))을 적용하면 동일한 요소가 모두 포함 된 컬렉션이 만들어집니다.

2

페치하는 동안 나는 비슷한 상황에 걸쳐 온 ListProject기본이보다는들 Iterable<T> findAll()에서 선언 된 CrudRepository인터페이스를 제공합니다. 따라서 내 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();
}

이것은 변환 논리 또는 외부 라이브러리 사용이 필요없는 가장 간단한 해결책이라고 생각합니다.


1

CactoosStickyList 에서 시도하십시오 :

List<String> list = new StickyList<>(iterable);

1

나는 보지 못했다 간단한 한 줄 솔루션 종속성하지 않고 있습니다. 나는 간단한 사용

List<Users> list;
Iterable<IterableUsers> users = getUsers();

// one line solution
list = StreamSupport.stream(users.spliterator(), true).collect(Collectors.toList());

0

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

또한 변환 할 수 있습니다 IterableA를 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();

위의 모든 Mutable유형이 확장 java.util.Collection됩니다.

참고 : 저는 Eclipse Collections의 커미터입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.