Dzięki Guava, możesz użyć Iterables.concat(Iterable<T> ...)
, tworzy widok na żywo wszystkich iterowalnych, połączonych w jedną (jeśli zmienisz iterowalne, połączona wersja również się zmieni). Następnie zawiń połączoną iterację z Iterables.unmodifiableIterable(Iterable<T>)
(nie widziałem wcześniej wymagania tylko do odczytu).
Z Iterables.concat( .. )
JavaDocs:
Łączy wiele elementów iteracyjnych w jedną iterowalną. Zwrócona iterowalna ma iterator, który przechodzi przez elementy każdej iterowalnej w danych wejściowych. Iteratory wejściowe nie są odpytywane, dopóki nie są potrzebne. Iterator zwracanej iteracji obsługuje, remove()
gdy obsługuje ją odpowiedni iterator wejściowy.
Chociaż nie oznacza to wyraźnie, że jest to podgląd na żywo, ostatnie zdanie sugeruje, że tak jest (obsługa Iterator.remove()
metody tylko wtedy, gdy iterator wspierający obsługuje, nie jest możliwa, chyba że używa się podglądu na żywo)
Przykładowy kod:
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);
Wynik:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 9999999]
Edytować:
Na żądanie od Damiana, oto podobna metoda, która zwraca aktywny widok kolekcji
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() {
}
}