Discuss / Java / 关于iterarot访问数组和索引访问数组的一些问题

关于iterarot访问数组和索引访问数组的一些问题

Topic source

24YOU

#1 Created at ... [Delete] [Delete and Lock User]

文中提到 

      通过Iterator遍历List永远是最高效的方式 

并没有说明为什么iterator访问是最高效的,或者说潜移默化的把这种访问方式认为是最高效的。

抱着这个疑问,我写了个简单代码来测试索引访问和迭代器访问的时间

List<Integer> list = new ArrayList(1000000);for(int i =0;i<1000000;i++){    list.add(i);}long startTime = System.currentTimeMillis();for(int i = 0 ; i<1000000; i++){    list.get(i);}long endtime = System.currentTimeMillis();System.out.println("按索引方式访问数组耗时:"+(endtime - startTime )+"ms");Iterator<Integer> iterator = list.iterator();long startTime2 = System.currentTimeMillis();while(iterator.hasNext()){    iterator.next();}long endtime2 = System.currentTimeMillis();System.out.println("按迭代器方式访问数组耗时:"+(endtime2 - startTime2 )+"ms");

有99%的情况是  按索引方式访问数组耗时最短(可以直接复制执行)。

然后我窥探了下两种方法源代码

 ****ArrayList.get(index)源代码

public E get(int index) {    rangeCheck(index);    return elementData(index);}

get干了什么事? 1. 检查是否访问越界  2.没有越界,返回索引对应元素。

迭代器next()源代码

public E next() {    checkForComodification();    int i = cursor;    if (i >= SubList.this.size)        throw new NoSuchElementException();    Object[] elementData = ArrayList.this.elementData;    if (offset + i >= elementData.length)        throw new ConcurrentModificationException();    cursor = i + 1;    return (E) elementData[offset + (lastRet = i)];}

next干了什么事? 1. 迭代器对象检查数组对象是否被修改过  2.同样检查越界等

单从代码角度看,结合实际运行情况,索引访问更快。

如果加入其他角度去考虑 这两种方式访问数组哪种**高效,**我认为是iterator对象更胜一筹。

写到这里我开始认为 文中的 高效 并不单单指获取元素的速度 而是正确性(也许只是我想多了)

为什么我会觉得iterator更好? 从多线程角度说一下我的理解。

1 .get方法没有任何防止出现多线程潜在问题的手段

2 .如果在for循环过程中,另一个线程将数组的元素删除或修改,结果将会错误(比如抛出越界异常)

3 .iterator.next()就做了某些手段 防止迭代器对象在循环没结束之前数组被某处代码修改。(修改之后如果再次next(),迭代器对象会抛出异常)

了解iterator的运作原理 

虽然说两者都抛出异常,但是迭代器只需要捕获一个异常即可(因为它只可能抛出那个异常),从设计角度来讲比较符合逻辑。

这就是一开始我读到  通过Iterator遍历List永远是最高效的方式  的疑惑,然后就开始捣鼓,最后总结出来的以上。(原来还是我太年轻

笼统的带过本该解释清楚的话会让人越来越懵,学的稀里糊涂

虽然我认为迭代器好,但我几乎没用过这东西。。。

廖雪峰

#2 Created at ... [Delete] [Delete and Lock User]

你写了这么多,都没说到要点。

List是接口,具体类怎么实现,使用者不知道也不想知道,所以不能假定索引方式遍历是高效的。但是编写的人知道怎么遍历最高效,所以由他负责实现Iterator,这样使用者完全不用关心List内部结构。

抽象才是目的。

24YOU

#3 Created at ... [Delete] [Delete and Lock User]

首先,感谢回复。

因为我才学习没多久,所以知识面没您广,指不出要点也很正常

我带上根据之前学的东西尝试去思考关于您那一段话,以及测试/查看代码,然后做出一些小结

抽象是一门艺术,我还不懂。

PBC

#4 Created at ... [Delete] [Delete and Lock User]

所以为什么是最高效的呀?

廖雪峰

#5 Created at ... [Delete] [Delete and Lock User]

谁写的XyzList,谁就要负责提供对应的Iterator。

作者自己的Iterator当然是最高效的,除非他写得有问题。


  • 1

Reply