Sets工具类--恰到好处的伪装

今天读了guava collect包中Sets类,该类从应用角度上讲,主要是集合的并交操作实现.

  • 交集 intersection()
  • 并集 union()
  • 差异 difference(S1,S2) S1包含而S2不包含的元素

这些方法的描述有一个共同点,都返回一个视图.

Returns an unmodifiable view of the ******* of two sets.

就是说这些方法不对内存进行操作,只返回一堆筛选过的引用.

在guava 15中,这些都基于内部的元素筛选方法:

UnmodifiableIterator filter(final Iterator unfiltered, final Predicate predicate)

该方法返回值为一个Iterator,View是实现了Iterable接口的,利用这个Iterator就可以完成迭代方法 iterator(),实现引用的迭代访问而不必去操作内存.下面看内部filter()方法,实现很简单(Guava 15),但是逻辑与方法实现分离的比较严重:

    public static  UnmodifiableIterator filter(final Iterator unfiltered, final Predicate predicate) {
        Preconditions.checkNotNull(unfiltered);
        Preconditions.checkNotNull(predicate);
        return new AbstractIterator() {
            protected T computeNext() {
                while(true) {
                    if(unfiltered.hasNext()) {
                        Object element = unfiltered.next();
                        if(!predicate.apply(element)) {
                            continue;
                        }

                        return element;
                    }

                    return this.endOfData();
                }
            }
        };
    }

这种设计很晦涩,不利于扩展.

下面来看guava 22的difference的实现,在后期版本中设计更为舒服一些,没有强制利用调用filter()返回AbstractIterator的形式,而是在各自方法里应用了不同方法应有的逻辑,实现了Set的protected方法如isEmpty() contains()等:

 public static  SetView difference(final Set set1, final Set set2) {
    checkNotNull(set1, "set1");
    checkNotNull(set2, "set2");

    return new SetView() {
      @Override
      public UnmodifiableIterator iterator() {
        return new AbstractIterator(){
          final Iterator itr = set1.iterator();
          @Override
          protected E computeNext() {
            while (itr.hasNext()) {
              E e = itr.next();
              if (!set2.contains(e)) {
                return e;
              }
            }
            return endOfData();
          }
        };
      }

      @Override
      public Stream stream() {
        return set1.stream().filter(e -> !set2.contains(e));
      }

      @Override
      public Stream parallelStream() {
        return set1.parallelStream().filter(e -> !set2.contains(e));
      }

      @Override
      public int size() {
        int size = 0;
        for (E e : set1) {
          if (!set2.contains(e)) {
            size++;
          }
        }
        return size;
      }

      @Override
      public boolean isEmpty() {
        return set2.containsAll(set1);
      }

      @Override
      public boolean contains(Object element) {
        return set1.contains(element) && !set2.contains(element);
      }
    };
  }

这里的设计很"投机取巧",关于Set<>应该有的方法,比如isEmpty(),contains(),iterator(),这个"假的Set"(SetView)都把这些工作转给了它的参数Set1和Set2来处理.
与这个类似:intersection与union只是做了简单的修改.不过public 的filter方法设计相对复杂,没有太看懂.

你可能感兴趣的:(Sets工具类--恰到好处的伪装)