006-guava 集合-集合工具类-集合扩展工具类

1、概述html

  须要实现本身的集合扩展。也许你想要在元素被添加到列表时增长特定的行为,或者你想实现一个Iterable,其底层其实是遍历数据库查询的结果集java

2、使用

2.一、ForwardingList装饰器

  针对全部类型的集合接口,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

2.二、PeekingIterator  

  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]
    }

2.三、AbstractIterator

实现你本身的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。

2.四、AbstractSequentialIterator

代器用其余方式表示会更简单。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的迭代器。