Iterable接口是Collection的父接口,主要用于遍历Collection集合中的元素。
方法如下:
//使用迭代器进行遍历
Iterator<T> iterator();
//使用Lambda表达式进行遍历
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
//可切割遍历
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
1. Iterator接口
Iterator接口:迭代器,迭代器的作用主要是遍历集合中的元素,所以Iterator对象必须依附于Collection对象
常用方法:
boolean hasNext():如果被迭代的集合元素还没有被遍历完,则返回true
Object.next():返回集合里的下一个元素
void remove():删除集合里上一次next方法返回的元素
void forEachRemaining(Consumer action):该方法为java8新增的默认方法,该方法可使用Lambda表达式来遍历集合元素
注意:
-
迭代器遍历期间,不能删除集合中的元素,否则出发快速失败(fail-fast)机制,出现异常ConcurrentModificationException
-
迭代时如果只是删除倒数第二个元素,不会报错,但是不建议这样操作。
-
对同一个迭代器对象只能使用一种方法的迭代方式,另一种将会被覆盖
-
不要多次使用it.next(),每次使用都是访问下一个对象,如果一个对象元素内包含了多个数据,则多次使用取数据,数据是错开的
-
迭代器是接口的原因:
-
因为集合类的数据结构不同,所以在存储的时候就不同,所以导致遍历的方式也不一样
-
最终就只能将迭代器定义成接口,使各种类去自己实现,保证了正确性
-
迭代器在具体实现类中以内部类的形式存在
-
package com.carl.javaadvanced.collection_demo;
import java.util.*;
public class ListTest {
public static void main(String[] args) {
List list=new ArrayList();
list.add(10);
list.add("java");
list.add(true);
//使用迭代器遍历集合中的元素--三种方法
//方法1:
Iterator iterator=list.iterator();
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
if (next.equals(10)) {
list.remove(next);//ConcurrentModificationException
}
}
//方法2:
//1.能用while循环写迭代程序,能不能用for循环?能,for循环效率高,因为用完的迭代器就成了垃圾
for(Iterator it=c.iterator();it.hasNext();) {
String s=(String)it.next();
System.out.println(s);
}
//方法3:
//forEachRemaining方法:Lamdba表达式遍历
iterator.forEachRemaining(obj-> System.out.println("forEachRemaining方法:"+obj));
//这种方式和Iterable接口中的forEach是一样的
}
}
2. Spliterator接口
Spliterator:可拆分迭代器,用于遍历容器中的元素,并拆分,然后并行处理
这里的容器可以是:数组、集合、IO通道、生成器函数
在JDK8.0以后,集合框架中所包含的所有数据结构都提供了默认的Spliterator实现
常用方法:
boolean tryAdvance(Consumer<? super T> action);//逐个处理元素--调用一次处理一个元素,处理lambda表达式
default void forEachRemaining(Consumer<? super T> action);//批量处理元素,循环tryAdvance()方法
Spliterator<T> trySplit();//对Spliterator进行分割,返回一个新的Spliterator可拆分迭代器
long estimateSize();//计算剩余多少元素需要遍历,使用tryAdvance和forEachRemaining遍历过的元素不会计算在内
default long getExactSizeIfKnown();//当迭代器拥有SIZED特征,返回剩余元素个数,否则返回-1
int characteristics();//返回当前对象有哪些**特征值**
default boolean hasCharacteristics(int characteristics);//是否具有characteristics特征值
default Comparator<? super T> getComparator();//如果Spliterator的list是通过Comparator排序,则返回Comparator对象
//如果Spliterator的list是通过自然排序,则返回null
特征值如下
特征 | 十六进制 | 十进制 | 含义 |
---|---|---|---|
ORDERED | 0x00000010 | 16 | 元素之间是有顺序的 |
DISTINCT | 0x00000001 | 1 | 元素之间不会重复 |
SORTED | 0x00000004 | 4 | 元素遵循定义的排序顺序 |
SIZED | 0x00000040 | 64 | 表示长度为有限个 |
NONNULL | 0x00000100 | 256 | 表示元素不能为空 |
IMMUTABLE | 0x00000400 | 1024 | 元素源不能修改(不能添加,替换或删除元素) |
CONCURRENT | 0x00001000 | 4096 | 多个线程安全同时修改元素源而无需外部同步 |
SUBSIZED | 0x00004000 | 16384 | 迭代器所分割得到的子迭代器也是有序的 |
原子类型的规范接口
Spliterator定义了三个原子类型的规范,分别是OffInt,OffLong,OffDouble,通过OfPrimitive封装了统一方法。OffInt通过引用IntConsumer来消费遍历的元素,OffLong通过LongConsumer来消费,OffDouble通过DoubleConsumer来消费。通过这种方式减少了装箱带来的性能消耗