迭代器(Iterator)
用于遍历某个数据结构实例中的所有数据,它取代了java集合框架中的Enumeration接口的位置
- 与Enumeration接口比较,迭代器的优点在于:
- ①增加了可以在遍历过程中进行删除操作的
- ②方法名进行了改进(感觉没什么卵用)
查看源码,发现其中的remove()方法和forEachRemaining()方法使用了default关键字
//代码清单:
default void remove() {
throw new UnsupportedOperationException("remove");
}
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
查阅资料显示:dufault关键字允许对接口中的方法进行实现,当子类继承该接口时,可以选择直接使用已经实现的方法,也可以选择自己实现,打破了对接口的惯性认知。
另外也出现了Consumer接口,查看源码。
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
可以比较容易的了解到:Consumer接口主要用于抽取不同类中存在的对对象相同的动作,例如一个自然数类,实数类和一个复数类都包含加减乘除等操作,为减少代码量,我们可以抽取这些共有的操作到多个Consumer接口(加法接口、减法接口、乘法接口、除法接口)中并实现,而在类中只需定义一个传入Consumer类型参数的方法即可。
而与Consumer接口相似的还有Function接口,代码如下
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
/**
* Returns a composed {@code Consumer} that performs, in sequence, this
* operation followed by the {@code after} operation. If performing either
* operation throws an exception, it is relayed to the caller of the
* composed operation. If performing this operation throws an exception,
* the {@code after} operation will not be performed.
*
* @param after the operation to perform after this operation
* @return a composed {@code Consumer} that performs in sequence this
* operation followed by the {@code after} operation
* @throws NullPointerException if {@code after} is null
*/
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
- Function与consumer接口的区别在于:
Function中的二次操作(compose)是对同一个对象进行两次相同的apply,而Consumer中的二次操作(andThen)是对同一个对象进行两此不同的操作,因此andThen方法还需传入一个Consumer类型参数
Spliterator
分割迭代器,用于对集合对象进行切分并记录切入点,最终目的是为了并行遍历被分割的元素。
下面是一个二分法分割迭代器
class TaggedArray<T> {
private final Object[] elements; // immutable after construction
TaggedArray(T[] data, Object[] tags) {
int size = data.length;
if (tags.length != size) throw new IllegalArgumentException();
this.elements = new Object[2 * size];
for (int i = 0, j = 0; i < size; ++i) {
elements[j++] = data[i];
elements[j++] = tags[i];
}
}
public Spliterator<T> spliterator() {
return new TaggedArraySpliterator<>(elements, 0, elements.length);
}
static class TaggedArraySpliterator<T> implements Spliterator<T> {
private final Object[] array;
private int origin; // current index, advanced on split or traversal
private final int fence; // one past the greatest index
TaggedArraySpliterator(Object[] array, int origin, int fence) {
this.array = array; this.origin = origin; this.fence = fence;
}
public void forEachRemaining(Consumer<? super T> action) {
for (; origin < fence; origin += 2)
action.accept((T) array[origin]);
}
public boolean tryAdvance(Consumer<? super T> action) {
if (origin < fence) {
action.accept((T) array[origin]);
origin += 2;
return true;
}
else // cannot advance
return false;
}
public Spliterator<T> trySplit() {
int lo = origin; // divide range in half
int mid = ((lo + fence) >>> 1) & ~1; // force midpoint to be even
if (lo < mid) { // split out left half
origin = mid; // reset this Spliterator's origin
return new TaggedArraySpliterator<>(array, lo, mid);
}
else // too small to split
return null;
}
public long estimateSize() {
return (long)((fence - origin) / 2);
}
public int characteristics() {
return ORDERED | SIZED | IMMUTABLE | SUBSIZED;
}
}
需要尝试进行多线程编程测试,有时间再说了。