1,定义容器能够foreach遍历
2.分析使用Arraylist foreach遍历时移除数据异常
java容器都具有用于遍历数据的foreach功能,如果自己定义一个容器类,如何实现这个语法呢?
第一步:实现Iterable接口
实现接口就要实现内部的方法(java8 default修饰的方法无需实现)
public class ForEachClass<T> implements Iterable<T> {
@Override
public Iterator iterator() {
return null;
}
}
第二步:实现接口方法
因为接口返回iterator对象,所以需要iterator是一个接口,所以必须定义一个实现iterator接口的类,然后实例化后成为对象再返回.
public class TestForEach {
//注1:T泛型作为该自定义容器数据的类型
static class ForEachClass<T> implements Iterable<T> {
Object[] value = null;
int current = 0;
//用于测试
public void addvalue(T... t) {
value = t;
}
//注2:每次foreach都会调用该方法
@Override
public Iterator<T> iterator() {
current = 0;
//参考list,用到是new,所以应该没问题
return new It();
}
注1:这里Iterable的泛型就是foreach中遍历数据所对应的类型.
注2:实现Iterable接口
Iterator是一个接口,需要自定义Iterator实现类,实现其hasNext和next方法
private class It implements Iterator<T> {
//注3:是否存在下一个元素,foreach停止的判断条件
@Override
public boolean hasNext() {
return value != null && current < value.length;
}
//注4:返回一下一个元素,作为foreach输出
@Override
public T next() {
T t = (T) value[current];
current++;
return t;
}
}
}
}
注3:是否存在下一个元素,foreach停止的判断条件
注4:返回一下一个元素,作为foreach输出
foreach遍历
ForEachClass<Integer test = new ForEachClass();
test.addvalue(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
for (Integer a : test) {//测试
System.out.print(a + " ");
}
迭代器遍历数据
当这个容器类可以通过foreach遍历数据后,这个类也能通过迭代器遍历数据
Iterator iterator =test.iterator();//注1,上步实现的接口
while(iterator.hasNext()){//注2:上步实现iterator接口的hasNext
Intenger i = iterator.next();//注3:上步实现iterator接口的next
}
}
注1,上步实现的接口
注2:上步实现iterator接口的hasNext
注3:上步实现iterator接口的next
上面3个方法均在实现foreach的时候实现了
foreach中删除数据报错
在list中,remove一个数据会导致foreach报ConcurrentModificationException异常
因为foreach会调用迭代器中next方法,next方法会调用checkForComodification,
public E next() {
checkForComodification();
....
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
因为list在remove和add的时候会改变modCount的值,expectedModCount只会在foeach开始赋值,在foreach每次调用next都会比较这两个值,看是否相等,如果不等就报错.估计设计这个的工程师只想让foreach只能作为遍历数据使用,防止出现其他的bug,毕竟foreach的细节不可见.如果要在遍历过程中删除和数据,可以使用迭代器.如下;
Iterator iterator =test.iterator();
while(iterator.hasNext()){
if (iterator.next().equals("3")){
iterator.remove();
}
}
除了容器类可以使用foreach遍历数据,数组也能通过这种方式遍历,如:
String[] arg =new String[10];
for(String s:arg) {
///XXXX
}
数组结构比较简单,而且没有方法,只有通过length知道大小,通过下标访问和写入,编译器就很轻松处理数组的foreach语法.