Guava学习之Collections ——Collection Helpers

Collection Helpers

Introduction

有时候需要写自己的扩展集合类。你可能需要当给list中添加元素的时候加入特殊的行为,或者想写一个由数据库查询支持的Iterable 。Guava 提供的工具类使得你在做这些任务的时候更容易。 (毕竟,我们自己的业务扩展了集合框架。)

Forwarding Decorators

对于所有的集合接口,For all the various collection interfaces, Guava 提供 Forwarding 抽象类以简化使用 decorator pattern(装饰器模式)。

Forwarding 类 定义了一个抽象方法, delegate(), 你应该重写去返回一个装饰类。其他的方法都直接被委托:例如,ForwardingList.get(int)是delegate().get(int)的简单实现。

通过子类化 ForwardingXXX 并实现 delegate() 方法, 可以只重写目标类中的选定方法,添加修饰的功能而不必自己委托每个方法。

此外, 许多方法实现了 standardMethod ,可以恢复预期的行为,提供一些AbstractList 的扩展或者JDK中的框架类中的相似的行为。

让我们举个例子。假设你想装饰一个列表,以便它记录添加到它里面的所有元素。当然,无论使用哪个方法添加元素add(int, E), add(E), 或者 addAll(Collection)—— 我们都希望记录元素,因此我们必须覆盖所有这些方法。

class AddLoggingList<E> extends ForwardingList<E> { 
    final List<E> delegate; // backing list 
    @Override 
    protected List<E> delegate() { 
        return delegate; 
    } 
    @Override 
    public void add(int index, E elem) { 
        log(index, elem); 
        super.add(index, elem); 
    } 
    @Override 
    public boolean add(E elem) { 
        return standardAdd(elem); // implements in terms of add(int, E) 
    } 
    @Override 
    public boolean addAll(Collection<? extends E> c) { 
        return standardAddAll(c); // implements in terms of add 
    } 
}

记住,默认情况下,所有方法都直接转发给委托,因此重写 ForwardingMap.put 将不会改变 ForwardingMap.putAll 的行为。 请注意覆盖必须更改其行为的每个方法,并确保装饰后的集合满足其契约。

通常, 抽象几何框架如AbstractList 提供的大多数方法在Forwarding 装饰器中也作为标准实现提供。

提供特殊视图的接口有时提供这些视图的标准实现。例如, ForwardingMap  提供 tandardKeySet, StandardValues, 与 StandardEntrySet, 其中每个方法都尽可能地将其方法委托给修饰过的映射,否则,它们将留下不能被委托为抽象的方法。其中每个方法都尽可能地将其方法委托给修饰过的映射,否则,它们将留下不能被委托为抽象的方法。

InterfaceForwarding Decorator
CollectionForwardingCollection
ListForwardingList
SetForwardingSet
SortedSetForwardingSortedSet
MapForwardingMap
SortedMapForwardingSortedMap
ConcurrentMapForwardingConcurrentMap
Map.EntryForwardingMapEntry
QueueForwardingQueue
IteratorForwardingIterator
ListIteratorForwardingListIterator
MultisetForwardingMultiset
MultimapForwardingMultimap
ListMultimapForwardingListMultimap
SetMultimapForwardingSetMultimap

PeekingIterator

有时候普通的Iterator 接口不够。

Iterators 支持方法 Iterators.peekingIterator(Iterator), 其 包装了一个 Iterator 返回 PeekingIterator, 是一种Iterator 的子类能够让你 peek() 在下一次调用next()时返回的元素。

注意: Iterators 返回 PeekingIterator 。peekingIterator 不支持 remove() 在调用 peek()之后.

让我们举个例子:复制一个列表,同时删除连续的重复元素。

List<E> result = Lists.newArrayList(); 
PeekingIterator<E> iter = Iterators.peekingIterator(source.iterator());
while (iter.hasNext()) {
    E current = iter.next(); 
    while (iter.hasNext() && iter.peek().equals(current)) { 
       // skip this duplicate element 
       iter.next(); 
    } 
    result.add(current); 
}

传统的实现方法包括跟踪前一个元素,并在特定条件下回退,但这是一项棘手且易出错的业务。 PeekingIterator 比较容易理解和使用。

AbstractIterator

实现你自己的 Iterator? AbstractIterator 使你的生活更轻松。

用一个例子来解释是最容易的。假设我们想要包装一个迭代器以便跳过空值。

public static Iterator<String> skipNulls(final Iterator<String> in) {
   return new AbstractIterator<String>() { 
       protected String computeNext() { 
           while (in.hasNext()) { 
              String s = in.next(); 
              if (s != null) { 
                 return s; 
              } 
           } 
           return endOfData(); 
       } 
    }; 
}

这里实现了一个方法 computeNext(), 仅仅计算下一个值,完成序列后,只返回 endOfData() 以标记迭代结束。

注意: AbstractIterator   继承unmodifiableIterator, 其禁止实现 remove()方法。如果你想要 iterator 支持 remove(), 那就不能继承 AbstractIterator.

AbstractSequentialIterator

 

一些迭代器更容易用其他方式表达。AbstractSequentialIterator 提供另一种表示迭代的方式。

Iterator<Integer> powersOfTwo = new AbstractSequentialIterator<Integer>(1) { 
    // note the initial value! 
    protected Integer computeNext(Integer previous) { 
        return (previous == 1 << 30) ? null : previous * 2; 
    } 
};

这里我们实现的方法 computeNext(T)接受先前的值作为参数。

注意,如果迭代器应该立即结束,则必须另外传递初始值,或者null。computeNext 假设空值意味着迭代结束-- AbstractSequentialIterator 不能用于实现可能返回空值的迭代器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值