1. 一段 BUG 引出迭代器
因为公司的代码蕴含业务逻辑局部,为了不便大家了解,写了一段简化的代码。这段代码是对列表 List 中的元素进行遍历,并且将满足肯定规定的元素(比方不能被 3 整除的数字)移除。刚开始这段代码是用 for 循环进行的,运行后会发现,有些元素明明不是 3 的倍数,却还是存在于链表之中。
// 筹备数据
LinkedList<Integer> list1 = new LinkedList<Integer>();
LinkedList<Integer> list2 = new LinkedList<Integer>();
for(int i=0;i<30;i++)
{list1.add(i);
list2.add(i);
}
//for 办法移除
System.out.println("For Remove");
for(int i =0;i<list1.size();i++)
{Integer num = list1.get(i);
if(num%3 != 0)
list1.remove(i);
}
for(Integer num : list1)
System.out.print(num + " ");
System.out.println();
程序的运行后果如下:
For Remove
0 2 3 5 6 8 9 11 12 14 15 17 18 20 21 23 24 26 27 29
对此,上面这段代码进行了改良,采纳迭代器依此拜访各元素。
// 迭代器 Iterator 办法移除
System.out.println("Iterator Remove");
Iterator<Integer> iter = list2.iterator();
while(iter.hasNext())
{Integer num = iter.next();
if(num%3 != 0) {iter.remove();
}
}
for(Integer num : list2)
System.out.print(num + " ");
System.out.println();
运行后果如下:
Iterator Remove
0 3 6 9 12 15 18 21 24 27
能够看的这次程序能够失常的运行了,不会漏掉 remove()操作后的一些元素。
这个例子给咱们的启发有两条:
在 for 循环外面能够拜访元素列表,但最好不要对元素列表进行移除操作;
如果想要在遍历过程中移除不适合的元素,最好应用迭代器;
2. 迭代器的相干介绍
迭代器是 java 定义的一个接口,在 java.util.Iterator 包下。该接口有四大办法,便于实现了该接口的汇合类进行拜访操作。
public interface Iterator<E>
{
E next();
boolean hasNextO;
void remove0;
default void forEachRemaining(Consumer<? super E> action);
}
在很多的汇合中曾经存在了拜访的办法,如 get(),为什么还须要迭代器 Iterator 这种接口的存在呢?这是因为,在 LinkedList 汇合中,迭代器的拜访效率是要高于 get 办法的,测试代码如下:
public static void ForMethod(List<Integer> list)
{long start = System.currentTimeMillis();
for(int i=0;i<list.size();i++)
{Integer num = list.get(i);
}
long t = System.currentTimeMillis() - start;
System.out.println("ForMethod:" + t + "ms");
}
public static void IteratorMethod(List<Integer> list)
{long start = System.currentTimeMillis();
Iterator<Integer> iter = list.iterator();
while(iter.hasNext())
{Integer num = iter.next();
}
long t = System.currentTimeMillis() - start;
System.out.println("IteratorMethod"+ t + "ms");
}
这里将产生一个大小为 100000 的链表,对两种办法进行测试,测试代码如下:
LinkedList<Integer> list = new LinkedList<Integer>();
for(int i=0;i<100000;i++)
{list.add(i);
}
ForMethod(list);
IteratorMethod(list);
程序的运行后果发现两者的差距是十分的大的,简直是近千倍的比率。
ForMethod:4327 ms
IteratorMethod 5 ms
这是因为链表中的 get 办法每次都是从头部查找,直到找到第 i 个元素为止。而 Iterator 办法更像以前学数据结构的时候,对链表进行依此遍历。也就是说,对于大小为 n 的链表,采纳 get 办法的工夫复杂度是 n(n+1)/2,而采纳迭代器的工夫复杂度是 n。随着链表大小的减少,拜访效率差距的呈线性增长。
谢谢大家可能耐着性子读到这里,心愿对大家有帮忙,如果喜爱的话请双击一下屏幕!笔心啦!