假设我有一个恒定数量的集合(例如3个ArrayLists)作为类的成员。现在,我想将所有元素公开给其他类,以便它们可以简单地遍历所有元素(理想情况下,只读)。 我正在使用guava集合,我想知道如何使用guava iterables / iterators在内部集合上生成逻辑视图,而不用制作临时副本。
答案 0 :(得分:111)
使用Guava,您可以使用Iterables.concat(Iterable<T> ...)
,它创建所有迭代的实时视图,连接成一个(如果您更改迭代,连接版本也会更改)。然后用Iterables.unmodifiableIterable(Iterable<T>)
包装连接的iterable(我之前没有看过只读的要求)。
来自Iterables.concat( .. )
JavaDocs:
将多个迭代组合成一个 单一可迭代。返回的可迭代 有一个遍历的迭代器 输入中每个可迭代的元素。 不轮询输入迭代器 直到必要。归来了 iterable的迭代器支持
remove()
当相应的输入迭代器时 支持它。
虽然这没有明确说明这是一个实时视图,但最后一句意味着它是(仅当支持迭代器支持它时才支持Iterator.remove()
方法,除非使用实时视图)< / p>
示例代码:
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() {
}
}
答案 1 :(得分:97)
使用Stream
的普通Java 8解决方案。
假设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);
}
答案 2 :(得分:10)
如果您至少使用Java 8,请参阅my other answer。
如果您已使用Google Guava,请参阅Sean Patrick Floyd's answer。
如果您遇到Java 7并且不想包含Google Guava,您可以使用不超过Iterables.concat()
和{{1}编写自己的(只读)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();
}
};
}
};
}
答案 3 :(得分:0)
您可以为其他List
创建一个新的addAll()
和List
。然后使用Collections.unmodifiableList()
返回一个不可修改的列表。
答案 4 :(得分:0)
以下是我的解决方案:
编辑 - 改变了一点代码
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();
}
};
}
};
}