GUAVA--集合(集合扩展工具类)

1、简介

有时候你须要实现本身的集合扩展。也许你想要在元素被添加到列表时增长特定的行为,或者你想实现一个 Itera ble,其底层其实是遍历数据库查询的结果集。Guava 为你,也为咱们本身提供了若干工具方法,以便让相似 的工做变得更简单。(毕竟,咱们本身也要用这些工具扩展集合框架。)java

2、Forwarding装饰器

针对全部类型的集合接口,Guava 都提供了 Forwarding 抽象类以简化装饰者模式的使用。数据库

Forwarding 抽象类定义了一个抽象方法:delegate(),你能够覆盖这个方法来返回被装饰对象。全部其余方法 都会直接委托给 delegate()。例如说:ForwardingList.get(int)实际上执行了 delegate().get(int)。框架

经过建立 ForwardingXXX 的子类并实现 delegate()方法,能够选择性地覆盖子类的方法来增长装饰功能,而不 须要本身委托每一个方法——译者注:由于全部方法都默认委托给 delegate()返回的对象,你能够只覆盖须要装饰 的方法。ide

此外,不少集合方法都对应一个”标准方法[standardxxx]”实现,能够用来恢复被装饰对象的默认行为,以提供 相同的优势。好比在扩展 AbstractList 或 JDK 中的其余骨架类时,可使用相似 standardAddAll 这样的方 法。工具

让咱们看看这个例子。假定你想装饰一个 List,让其记录全部添加进来的元素。固然,不管元素是用什么方 法——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); // 用add(int, E)实现
		}

		@Override
		public boolean addAll(Collection<? extends E> c) {
			return standardAddAll(c); // 用add实现
		}
	}

默认状况下,全部方法都直接转发到被代理对象,所以覆盖 ForwardingMap.put 并不会改变 Forwardin gMap.putAll 的行为。当心覆盖全部须要改变行为的方法,而且确保装饰后的集合知足接口契约。code

一般来讲,相似于 AbstractList 的抽象集合骨架类,其大多数方法在 Forwarding 装饰器中都有对应的”标准方 法”实现。对象

对提供特定视图的接口,Forwarding 装饰器也为这些视图提供了相应的”标准方法”实现。例如,Forwarding Map 提供 StandardKeySet、StandardValues 和 StandardEntrySet 类,它们在能够的状况下都会把本身的 方法委托给被装饰的 Map,把不能委托的声明为抽象方法。继承

3、PeekingIterator

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

Iterators 提供一个 Iterators.peekingIterator(Iterator)方法,来把 Iterator 包装为 PeekingIterator,这是 Iterator 的子类,它能让你事先窥视[peek()]到下一次调用 next()返回的元素。

注意:Iterators.peekingIterator 返回的 PeekingIterator 不支持在 peek()操做以后调用remove()方法。举个例子:复制一个 List,并去除连续的重复元素。

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)) {
			// 跳太重复的元素
			iter.next();
		}
		result.add(current);
	}

传统的实现方式须要记录上一个元素,并在特定状况下后退,但这很难处理且容易出错。相较而言, PeekingIterator 在理解和使用上就比较直接了。

4、AbstractIterator

实现你本身的 Iterator?AbstractIterator 让生活更轻松。

用一个例子来解释 AbstractIterator 最简单。比方说,咱们要包装一个 iterator 以跳过空值。

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()方法。若是你须要支持 remove()的迭代器,就不该该继承 AbstractIterator。

AbstractSequentialIterator

有一些迭代器用其余方式表示会更简单。AbstractSequentialIterator 就提供了表示迭代的另外一种方式。

Iterator<Integer> powersOfTwo = new AbstractSequentialIterator<Integer>(1) { 
		// 注意初始值1!
		protected Integer computeNext(Integer previous) {
			return (previous == 1 << 30) ? null : previous * 2;
		}
	};

咱们在这儿实现了 computeNext(T)方法,它能接受前一个值做为参数。

注意,你必须额外传入一个初始值,或者传入 null 让迭代当即结束。由于 computeNext(T)假定 null 值意味着 迭代的末尾——AbstractSequentialIterator 不能用来实现可能返回 null 的迭代器。

相关文章
相关标签/搜索