1、概述html
須要實現本身的集合擴展。也許你想要在元素被添加到列表時增長特定的行爲,或者你想實現一個Iterable,其底層其實是遍歷數據庫查詢的結果集java
針對全部類型的集合接口,Guava都提供了Forwarding抽象類以簡化裝飾者模式的使用。git
Forwarding抽象類定義了一個抽象方法:delegate(),你能夠覆蓋這個方法來返回被裝飾對象。全部其餘方法都會直接委託給delegate()。例如說:ForwardingList.get(int)實際上執行了delegate().get(int)。數據庫
示例:爲null設置默認值ide
class ListWithDefault<E> extends ForwardingList<E> { final E defaultValue; final List<E> delegate; ListWithDefault(List<E> delegate, E defaultValue) { this.delegate = delegate; this.defaultValue = defaultValue; } @Override protected List delegate() { return delegate; } @Override public E get(int index) { E v = super.get(index); return (v == null ? defaultValue : v); } @Override public Iterator<E> iterator() { final Iterator<E> iter = super.iterator(); return new ForwardingIterator<E>() { @Override protected Iterator<E> delegate() { return iter; } @Override public E next() { E v = super.next(); return (v == null ? defaultValue : v); } }; } } @Test public void testListWithDefault() { List<String> names = new ListWithDefault<>( Arrays.asList("Alice", null, "Bob", "Carol", null), "UNKNOWN" ); names.forEach(p -> System.out.print(p + ",")); //Alice,UNKNOWN,Bob,Carol,UNKNOWN, System.out.println(); System.out.println(names);//[Alice, null, Bob, Carol, null] }
注意: toString()方法仍然返回委託的 toString(),它不知道默認值。還有一些其餘方法必須 @Override 以及更完整的實現。this
Iterators提供一個Iterators.peekingIterator(Iterator)方法,來把Iterator包裝爲PeekingIterator,這是Iterator的子類,它能讓你事先窺視[peek()]到下一次調用next()返回的元素。google
注意:Iterators.peekingIterator返回的PeekingIterator不支持在peek()操做以後調用remove()方法。spa
示例、複製一個List,並去除連續的重複元素。code
@Test public void testpeekingIterator() { List<String> source = Lists.newArrayList("a","b","b","c","a"); List<String> result = Lists.newArrayList(); System.out.println(source);//[a, b, b, c, a] PeekingIterator<String> iter = Iterators.peekingIterator(source.iterator()); while (iter.hasNext()) { String current = iter.next(); while (iter.hasNext() && iter.peek().equals(current)) { //跳太重複的元素 iter.next(); } result.add(current); } System.out.println(result);//[a, b, c, a] }
實現你本身的Iteratorhtm
示例:包裝一個iterator以跳過空值
public 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(); } }; } @Test public void testAbstractIterator() { List<String> list=Lists.newArrayList("0","a",null); Iterator<String> iterator = skipNulls(list.iterator()); iterator.forEachRemaining(p-> System.out.print(p+","));//0,a, }
實現了computeNext()方法,來計算下一個值。若是循環結束了也沒有找到下一個值,請返回endOfData()代表已經到達迭代的末尾。
注意:AbstractIterator繼承了UnmodifiableIterator,因此禁止實現remove()方法。若是你須要支持remove()的迭代器,就不該該繼承AbstractIterator。
代器用其餘方式表示會更簡單。AbstractSequentialIterator 就提供了表示迭代的另外一種方式。
示例
@Test public void testAbstractSequentialIterator() { Iterator<Integer> powersOfTwo = new AbstractSequentialIterator<Integer>(1) { // 注意初始值1! protected Integer computeNext(Integer previous) { return (previous == 1 << 12) ? null : previous * 2; } }; powersOfTwo.forEachRemaining(p -> System.out.print(p + ","));//1,2,4,8,16,32,64,128,256,512,1024,2048,4096, }
在這兒實現了computeNext(T)方法,它能接受前一個值做爲參數。
注意,你必須額外傳入一個初始值,或者傳入null讓迭代當即結束。由於computeNext(T)假定null值意味着迭代的末尾——AbstractSequentialIterator不能用來實現可能返回null的迭代器。