Iterable<T>:迭代器接口(就是为了遍历集合)@since1.5
Iterator<T>iterator();(取的集合的迭代器,JDK1.5之前直接写在collection接口中)
Iterator<T>接口的方法 Scanner也是Iterator接口的实现类
迭代器:为了遍历集合而生。—迭代器模式
Collection接口中也有Iterator<T>iterator();方法
Iterator<T>接口的两个核心方法 :
boolean hasNext(); 判断是否还有元素
E next();取得下一个元素
之前用for循环遍历,能遍历是因为各个集合都有内置的迭代器
public class IteratorTest{
public static void main(String[] args){
List<String> list=new ArrayList<>();
list.add("hello");
list.add("world");
list.add("hello");
list.add("java");
System.out.println(list);
Iterator iterator=list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
结果:
1、迭代输出Iterator—只能从前向后输出—Collection接口提供(只有set和list有Iterator对象,map没有)
调用Collection集合子类的Iterator方法取得内置的迭代器(Iterator iterator=list.iterator();),使用以下输出格式
while(iterator.hasNext()){
System.out.println(iterator.next());
}
2、双向迭代接口listIterator—List接口提供,set不支持
除了由hashNext()方法和next()方法以外,还有
hasPrevious():判断是否由上一个元素
pervious():取得上一个元素
ListIterator iterator=list.listIterator();
while(iterator.hasPrevious()){
System.out.println(iterator.previous());
}
运行结果为空:要想使用从后往前遍历输出,首先至少要从前向后遍历一个次能使用
3、Enumeration(JDK1.0)枚举输出—Vector类支持
hasMoreElements():判断是否由下一个元素
nextElements():取得下一个元素
Vector<String> vector= new Vector<>();
vector.add("hello");
vector.add("world");
vector.add("hello");
vector.add("java");
System.out.println(vector);
Enumeration<String> enumeration=vector.elements();
while(enumeration.hasMoreElements()){
System.out.println(enumeration.nextElement());
}
4、for-eash输出:用for-eash输出的本质,各个集合都内置了迭代器,还是调用了迭代器
for(String s:vector){
System.out.println(s);//其余代码同上
}
Fail-fast机制
Collections中的方法
public static <T> boolean addAll(Collection<?superT>c,T...elements)
java.util.ConcurrentModificationException发生在Collection集合使用迭代器遍历时,使用了集合类提供的修改集合内容方法报错,而如果使用iterator迭代器的remove()方法不会出现此错误。
ArrayList的内部类中itr中
final void checkForComodification(){
if(modCount!=expectedModCount)
Throw new ConcurrentModificationException();
}
Collection中的modCount表示当前集合表示当前集合修改的次数(在并发的场景下,用户在遍历时,修改内容,有一个值告知别人改了没改,保证用户不会脏读)
脏读:我现在看到的数据不是最新的
modCount保证了用户看到的值一定是当前集合的最新值
expectedModCount迭代器中记录当前集合的修改次数
当取得集合迭代器时(即调用list.iterator()---->return new Itr()-->expectedModCount=modCount):expectedModCount=modCount,换言之,迭代器就是当前集合的副本,拷贝
public static void main(String[] args){
List<String> list = new ArrayList<>();
Collections.addAll(list,"A","B","c","D","E","B");
//modCount=6
Iterator<String> iterator = list.iterator();
//取得集合迭代器(取得当前集合的副本)
//expectedModCount=modCount=6
while(iterator.hasNext()){
String str=iterator.next();
//next()调用checkForComodification()检查副本中的expectedModCount是否等于集合的modCount
//每当在遍历时做了变化,下次遍历时一定会出错,告诉当前的集合可能已经被修改,你看到的值不一是最新的
if(str.equals("B")){
list.remove("B");
//modCount=modCount+1=7
continue;
}
System.out.println(str);
}
System.out.println(list);
}
在有迭代的情况下,list.remove("B")会出错。
快速失败策略保证了所有用户在进行迭代遍历集合是,拿到的数据一定是最新的数据(避免脏读产生)
Fail-safe:不产生ConcurrentModificationException异常
juc包下的所有线程安全集合:ArrayList、Vector、 LinkedList都在Java.util包下
Juc:并发安全包(CopyOnWriteArrayList,concurrentHashMap??)
以后再迭代器遍历时,不要修改集合内容
while(iterator.hasNext()){
String str=iterator.next();
//next()调用checkForComodification()检查副本中的expectedModCount是否等于集合的modCount
//每当在遍历时做了变化,下次遍历时一定会出错,告诉当前的集合可能已经被修改,你看到的值不一是最新的
if(str.equals("B")){
iterator.remove();
//modCount=modCount+1=7
continue;
}
System.out.println(str);
}
为什么iterator.remove();不报错??
因为: