今天读了guava collect包中Sets类,该类从应用角度上讲,主要是集合的并交操作实现.
- 交集 intersection()
- 并集 union()
- 差异 difference(S1,S2) S1包含而S2不包含的元素
这些方法的描述有一个共同点,都返回一个视图.
Returns an unmodifiable view of the ******* of two sets.
就是说这些方法不对内存进行操作,只返回一堆筛选过的引用.
在guava 15中,这些都基于内部的元素筛选方法:
UnmodifiableIterator<T> filter(final Iterator<T> unfiltered, final Predicate<? super T> predicate)
该方法返回值为一个Iterator,View是实现了Iterable接口的,利用这个Iterator就可以完成迭代方法 iterator(),实现引用的迭代访问而不必去操作内存.下面看内部filter()方法,实现很简单(Guava 15),但是逻辑与方法实现分离的比较严重:
public static <T> UnmodifiableIterator<T> filter(final Iterator<T> unfiltered, final Predicate<? super T> 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 <E> SetView<E> difference(final Set<E> set1, final Set<?> set2) {
checkNotNull(set1, "set1");
checkNotNull(set2, "set2");
return new SetView<E>() {
@Override
public UnmodifiableIterator<E> iterator() {
return new AbstractIterator<E>(){
final Iterator<E> 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<E> stream() {
return set1.stream().filter(e -> !set2.contains(e));
}
@Override
public Stream<E> 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方法设计相对复杂,没有太看懂.