내 응용 프로그램에서 타사 라이브러리 (MongoDB의 스프링 데이터가 정확함)를 사용합니다.
이 라이브러리의 메소드는 반환 Iterable<T>
하지만 나머지 코드는 예상 Collection<T>
합니다.
어딘가에 빠르게 변환 할 수있는 유틸리티 방법이 있습니까? foreach
그런 간단한 일을 위해 코드에 많은 루프를 만드는 것을 피하고 싶습니다 .
내 응용 프로그램에서 타사 라이브러리 (MongoDB의 스프링 데이터가 정확함)를 사용합니다.
이 라이브러리의 메소드는 반환 Iterable<T>
하지만 나머지 코드는 예상 Collection<T>
합니다.
어딘가에 빠르게 변환 할 수있는 유틸리티 방법이 있습니까? foreach
그런 간단한 일을 위해 코드에 많은 루프를 만드는 것을 피하고 싶습니다 .
답변:
함께 구아바 당신이 사용할 수있는 Lists.newArrayList (의 Iterable) 또는 Sets.newHashSet (의 Iterable를) 다른 유사한 방법들. 이것은 물론 모든 요소를 메모리에 복사합니다. 그것이 받아 들일 수 없다면, 이것들과 작동하는 코드는 Iterable
오히려 사용해야한다고 생각합니다 Collection
. 구아바는 또한 당신이 할 수있는 일을하는 편리한 방법을 제공하는 일이 Collection
를 사용하여 Iterable
(예 : Iterables.isEmpty(Iterable)
또는 Iterables.contains(Iterable, Object)
),하지만 성능에 영향이 더 분명하다.
Lists.newArrayList(Iterable).clear()
선형 또는 일정 시간 작동입니까?
Collection
보기 위해 구현할 수 없거나 Iterable
비효율적이라는 점을 감안할 때 나에게 그렇게하는 것이 의미가 없습니다.
Iterables.concat()
있지만 : Iterable
a가 아닌 을 제공합니다 . Collection
(
Iterables.concat()
입니다. 훨씬 더 긴 대답은 Collection
... 왜 이것이 더 일반적으로 지원되지 않는지 궁금합니다.
추가 라이브러리를 사용하지 않고 JDK 8 이상에서 :
Iterator<T> source = ...;
List<T> target = new ArrayList<>();
source.forEachRemaining(target::add);
편집 : 위의 내용은입니다 Iterator
. 당신이 다루고있는 경우 Iterable
,
iterable.forEach(target::add);
iterable.forEach(target::add);
이것에 대한 고유 한 유틸리티 메소드를 작성할 수도 있습니다.
public static <E> Collection<E> makeCollection(Iterable<E> iter) {
Collection<E> list = new ArrayList<E>();
for (E item : iter) {
list.add(item);
}
return list;
}
Iterable
에하는 것이 Collection
유일한 문제는, 내가 큰 제 3 자 컬렉션 라이브러리를 가져 오는 동안이 방법을 선호하는 것입니다.
다음을 사용하는 Java 8을 사용한 간결한 솔루션 java.util.stream
:
public static <T> List<T> toList(final Iterable<T> iterable) {
return StreamSupport.stream(iterable.spliterator(), false)
.collect(Collectors.toList());
}
IteratorUtils
에서commons-collections
IteratorUtils.toList()
Java 5 이전 방식으로 반복자를 사용하여 새로 작성된 목록에 요소를 하나씩 추가합니다. 간단하고 아마도 가장 빠르지 만 바이너리에 734 kB를 추가 하고이 방법이 가장 좋은 것으로 밝혀지면 스스로 할 수 있습니다.
IteratorUtils
from commons-collections
may help (최신 안정 버전 3.2.1에서는 제네릭을 지원하지 않지만) :
@SuppressWarnings("unchecked")
Collection<Type> list = IteratorUtils.toList(iterable.iterator());
버전 4.0 (현재 SNAPSHOT에 있음)은 제네릭을 지원하며 @SuppressWarnings
.
업데이트 : CactoosIterableAsList
에서 확인하십시오 .
IterableUtils.toList(Iterable)
편리한 방법이며 IteratorUtils
후드에서 사용되지만 null 안전합니다 (와 달리 IteratorUtils.toList
).
에서 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()
선형 또는 일정 시간 작동입니까?
addAll
이름에서 알 수 있듯이 소스 코드를 추가 하여 반복자 값을 하나씩 복사합니다. 보기가 아닌 사본을 작성합니다.
CollectionUtils
여분의 라인에서 컬렉션 생성을 건너 뛸 수있는 방법이 없다는 것이 얼마나 유감입니다 .
Iterable은 약속이 없지만 모든 컬렉션은 유한하다는 것을 잊지 마십시오. Iterable이 있으면 Iterator를 얻을 수 있습니다.
for (piece : sthIterable){
..........
}
다음으로 확장됩니다 :
Iterator it = sthIterable.iterator();
while (it.hasNext()){
piece = it.next();
..........
}
it.hasNext ()는 false를 반환하지 않아도됩니다. 따라서 일반적인 경우 모든 Iterable을 Collection으로 변환 할 수는 없습니다. 예를 들어, 모든 양수의 자연수를 반복하고,주기가 같은 것을 반복하여 동일한 결과를 반복해서 반복 할 수 있습니다.
그렇지 않으면 : Atrey의 대답은 꽤 좋습니다.
이것은 귀하의 질문에 대한 답변이 아니지만 귀하의 문제에 대한 해결책이라고 생각합니다. 인터페이스 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);
}
}
이상적으로는 위의 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 등)에 대해 유사한 유틸리티를 구현합니다. 나는 이것이 이미 구아바의 일부라고 생각하지만 찾지 못했습니다.
즉시 전화로 contains
, containsAll
, equals
, hashCode
, remove
, retainAll
, size
또는toArray
, 당신은 어쨌든 요소를 통과해야 할 것이다.
가끔과 같은 메소드를 호출 isEmpty
하거나 clear
컬렉션을 느리게 만드는 것이 더 낫다고 생각합니다. 예를 들어 백업을 할 수 있습니다ArrayList
이전에 반복 된 요소를 저장하기 있습니다.
나는 어떤 도서관에서 그런 클래스를 알지 못하지만 작성하는 것은 매우 간단한 연습이어야합니다.
자바 8에서는 당신은 모든 요소를 추가하려면이 작업을 수행 할 수 있습니다 Iterable
에 Collection
그것을 반환 :
public static <T> Collection<T> iterableToCollection(Iterable<T> iterable) {
Collection<T> collection = new ArrayList<>();
iterable.forEach(collection::add);
return collection;
}
@Afreys의 답변에서 영감을 얻었습니다.
RxJava는 망치이기 때문에 손톱처럼 보이기 때문에 할 수 있습니다
Observable.from(iterable).toList().toBlocking().single();
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);
}
}
비고
페치하는 동안 나는 비슷한 상황에 걸쳐 온 List
의 Project
기본이보다는들 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();
}
이것은 변환 논리 또는 외부 라이브러리 사용이 필요없는 가장 간단한 해결책이라고 생각합니다.
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
A를 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의 커미터입니다.