답변:
Guava를 사용하면를 사용할 수 있습니다 Iterables.concat(Iterable<T> ...)
. 모든 이터 러블의 라이브 뷰를 생성하고 하나로 연결합니다 (이터 러블을 변경하면 연결된 버전도 변경됨). 그런 다음 연결된 iterable을 Iterables.unmodifiableIterable(Iterable<T>)
(이전에 읽기 전용 요구 사항을 보지 못했던)로 래핑합니다 .
로부터 Iterables.concat( .. )
JavaDoc을 :
여러 반복 가능 항목을 단일 반복 가능 항목으로 결합합니다. 반환 된 이터 러블에는 입력에서 각 이터 러블의 요소를 순회하는 이터레이터가 있습니다. 입력 반복자는 필요할 때까지 폴링되지 않습니다. 반환 된 이터 러블의 이터레이터는
remove()
해당 입력 이터레이터가 지원할 때 지원합니다.
이것이 라이브 뷰라고 명시 적으로 말하지는 않지만 마지막 문장은 그것이 있음을 암시합니다 ( Iterator.remove()
백킹 반복자가 지원하는 경우에만 메서드를 지원하는 것은 라이브 뷰를 사용하지 않는 한 불가능합니다)
샘플 코드 :
final List<Integer> first = Lists.newArrayList(1, 2, 3);
final List<Integer> second = Lists.newArrayList(4, 5, 6);
final List<Integer> third = Lists.newArrayList(7, 8, 9);
final Iterable<Integer> all =
Iterables.unmodifiableIterable(
Iterables.concat(first, second, third));
System.out.println(all);
third.add(9999999);
System.out.println(all);
산출:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 9999999]
편집하다:
Damian의 요청에 따라 라이브 컬렉션 뷰를 반환하는 유사한 메서드가 있습니다.
public final class CollectionsX {
static class JoinedCollectionView<E> implements Collection<E> {
private final Collection<? extends E>[] items;
public JoinedCollectionView(final Collection<? extends E>[] items) {
this.items = items;
}
@Override
public boolean addAll(final Collection<? extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
for (final Collection<? extends E> coll : items) {
coll.clear();
}
}
@Override
public boolean contains(final Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(final Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean isEmpty() {
return !iterator().hasNext();
}
@Override
public Iterator<E> iterator() {
return Iterables.concat(items).iterator();
}
@Override
public boolean remove(final Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(final Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(final Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public int size() {
int ct = 0;
for (final Collection<? extends E> coll : items) {
ct += coll.size();
}
return ct;
}
@Override
public Object[] toArray() {
throw new UnsupportedOperationException();
}
@Override
public <T> T[] toArray(T[] a) {
throw new UnsupportedOperationException();
}
@Override
public boolean add(E e) {
throw new UnsupportedOperationException();
}
}
/**
* Returns a live aggregated collection view of the collections passed in.
* <p>
* All methods except {@link Collection#size()}, {@link Collection#clear()},
* {@link Collection#isEmpty()} and {@link Iterable#iterator()}
* throw {@link UnsupportedOperationException} in the returned Collection.
* <p>
* None of the above methods is thread safe (nor would there be an easy way
* of making them).
*/
public static <T> Collection<T> combine(
final Collection<? extends T>... items) {
return new JoinedCollectionView<T>(items);
}
private CollectionsX() {
}
}
Iterables.concat
이 Iterable
아니라 Collection
. Collection
보기 가 필요합니다 .
size()
내가 필요한 것입니다. add()
예외를 던지는 것이 좋습니다.이 방법은 신경 쓰지 않습니다. Collections API가 손상되어 아무도 그것에 대해 아무것도 할 수 없습니다. Collection.add()
,, Iterator.remove()
어쩌구.
일반 자바 사용 a (8 개) 솔루션 Stream
.
가정 private Collection<T> c, c2, c3
합니다.
하나의 솔루션 :
public Stream<T> stream() {
return Stream.concat(Stream.concat(c.stream(), c2.stream()), c3.stream());
}
또 다른 해결책 :
public Stream<T> stream() {
return Stream.of(c, c2, c3).flatMap(Collection::stream);
}
가정 private Collection<Collection<T>> cs
:
public Stream<T> stream() {
return cs.stream().flatMap(Collection::stream);
}
Java 8 이상을 사용하는 경우 다른 답변을 참조하십시오 .
이미 Google Guava를 사용하고 있다면 Sean Patrick Floyd의 답변을 참조하십시오 .
Java 7에 갇혀 있고 Google Guava를 포함하고 싶지 않다면 and Iterables.concat()
이하를 사용하여 자신 만의 (읽기 전용) 작성할 수 있습니다 .Iterable
Iterator
public static <E> Iterable<E> concat(final Iterable<? extends E> iterable1,
final Iterable<? extends E> iterable2) {
return new Iterable<E>() {
@Override
public Iterator<E> iterator() {
return new Iterator<E>() {
final Iterator<? extends E> iterator1 = iterable1.iterator();
final Iterator<? extends E> iterator2 = iterable2.iterator();
@Override
public boolean hasNext() {
return iterator1.hasNext() || iterator2.hasNext();
}
@Override
public E next() {
return iterator1.hasNext() ? iterator1.next() : iterator2.next();
}
};
}
};
}
@SafeVarargs
public static <E> Iterable<E> concat(final Iterable<? extends E>... iterables) {
return concat(Arrays.asList(iterables));
}
public static <E> Iterable<E> concat(final Iterable<Iterable<? extends E>> iterables) {
return new Iterable<E>() {
final Iterator<Iterable<? extends E>> iterablesIterator = iterables.iterator();
@Override
public Iterator<E> iterator() {
return !iterablesIterator.hasNext() ? Collections.emptyIterator()
: new Iterator<E>() {
Iterator<? extends E> iterableIterator = nextIterator();
@Override
public boolean hasNext() {
return iterableIterator.hasNext();
}
@Override
public E next() {
final E next = iterableIterator.next();
findNext();
return next;
}
Iterator<? extends E> nextIterator() {
return iterablesIterator.next().iterator();
}
Iterator<E> findNext() {
while (!iterableIterator.hasNext()) {
if (!iterablesIterator.hasNext()) {
break;
}
iterableIterator = nextIterator();
}
return this;
}
}.findNext();
}
};
}
당신은 그것에 대해 새로운 List
것과 addAll()
당신의 다른 것을 만들 수 있습니다 List
. 그런 다음 수정 불가능한 목록을 Collections.unmodifiableList()
.
ArrayList
단지 공간과 통화 할당 System.arraycopy()
후드 아래를. 그것보다 훨씬 더 효율적일 수는 없습니다.
이에 대한 내 해결책은 다음과 같습니다.
편집-약간의 코드 변경
public static <E> Iterable<E> concat(final Iterable<? extends E> list1, Iterable<? extends E> list2)
{
return new Iterable<E>()
{
public Iterator<E> iterator()
{
return new Iterator<E>()
{
protected Iterator<? extends E> listIterator = list1.iterator();
protected Boolean checkedHasNext;
protected E nextValue;
private boolean startTheSecond;
public void theNext()
{
if (listIterator.hasNext())
{
checkedHasNext = true;
nextValue = listIterator.next();
}
else if (startTheSecond)
checkedHasNext = false;
else
{
startTheSecond = true;
listIterator = list2.iterator();
theNext();
}
}
public boolean hasNext()
{
if (checkedHasNext == null)
theNext();
return checkedHasNext;
}
public E next()
{
if (!hasNext())
throw new NoSuchElementException();
checkedHasNext = null;
return nextValue;
}
public void remove()
{
listIterator.remove();
}
};
}
};
}
hasNext()
및 의 역할을 뒤집습니다 next()
. 첫 번째는 반복기의 상태를 변경하지만 두 번째는 그렇지 않습니다. 반대 방향이어야합니다. 호출 next()
호출하지 않고 hasNext()
항상 얻을 것입니다 null
. 호출 hasNext()
하지 않고 호출 next()
하면 요소가 버려집니다. 당신 next()
도 던지지 NoSuchElementException
않고 대신을 반환합니다 null
.