⑧循环遍历Map、List的方法,哪个更快?

(1)遍历Map的四种方法

<span style="font-size:18px;background-color: rgb(153, 255, 255);">public static void main(String[] args) {

  Map<String, String> map = new HashMap<String, String>();
  map.put("1", "value1");
  map.put("2", "value2");
  map.put("3", "value3");
  
  //第一种:普遍使用,二次取值
  System.out.println("通过Map.keySet遍历key和value:");
  for (String key : map.keySet()) {
   System.out.println("key= "+ key + " and value= " + map.get(key));
  }
  
  //第二种
  System.out.println("通过Map.entrySet使用iterator遍历key和value:");
  Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
  while (it.hasNext()) {
   Map.Entry<String, String> entry = it.next();
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
  }
  
  //第三种:推荐,尤其是容量大时
  System.out.println("通过Map.entrySet遍历key和value");
  for (Map.Entry<String, String> entry : map.entrySet()) {
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
  }

  //第四种
  System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
  for (String v : map.values()) {
   System.out.println("value= " + v);
  }
 }</span>

(2)遍历List的方法

 第一种:   
   for(Iterator<类型>    it    =    list.iterator();    it.hasNext();    )    {   //比如类型为String
       ....   
   }   
   这种方式在循环

执行过程中会进行数据锁定,       性能稍差,       同时,如果你想在循环过程中去掉某个元素,只能调用it.remove方法,      不能使用list.remove方法,       否则一定出并发访问的错误.     
       
   第二种:     
List<Stirng> list=new ArrayLiast<String>();
     for(  类型        a       :       list)       {     //注意,这里的类型必须与先前申明的list类型对应,a是一个参数名。
           System.out.println(a);  .....     
     }     
     内部调用第一种,       换汤不换药,       这种循环方式还有其他限制,       不建议使用它     
       
    第三种:      
     for(int       i=0;       i<list.size();       i++)       {     
             类型       a       =       list.get(i);     
             ...     
     }     
     内部不锁定,       效率最高,       但是当写多线程时要考虑并发操作的问题


(3)效率问题,那个更快更好?

   这里引用别人的一个帖子,内容如下:


简单:

Iterator 主要性能开销在next方法体,其一:对记录集进行检测,如果在迭代的过程中,记录集有被修改,会抛出异常;其二:next方法体内有try...catch方法体,这也会影响性能,JVM不能对try...catch块内的代码进行优化。
而for因为不管数据被中途修改,也不进行异常处理,所以当然快啦

 

详细:

ArrayList的iterator是在AbstractList里面的
它的next方法如下:

Java code
    
    
public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } }

而其中的get为:
Java code
    
    
public E get(int index) { rangeCheck(index); checkForComodification(); return l.get(index+offset); }

看到这个l.get(index+offset)了没?这个l就是AbstractList本身
所以,最终调用的是ArrayList的get:
Java code
    
    
public E get(int index) { RangeCheck(index); return (E) elementData[index]; }

总结:对ArrayList而言,for里面的get比较单纯,而iterator的next多了checkForComodification,rangeCheck等,所以变慢了。


引用回复:
把arrayList改为LinkedList,就知道结果了


LinkedList又是另外一个话题了,不过LZ的程序千万别不动脑筋的把ArrayList变成LinkedList呀。
LZ的程序的for循环,如果用LinkedList的话,慢死你没商量!
理由很简单LinkedList的get(int index)是调用AbstractSequentialList的public E get(int index):
Java code
    
    
public E get(int index) { try { return listIterator(index).next(); } catch (NoSuchElementException exc) { throw new IndexOutOfBoundsException("Index: "+index); } }

而listIterator(index)的最终是要调LinkedList的ListItr(int index):
Java code
    
    
ListItr(int index) { if (index < 0 || index > size) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+size); if (index < (size >> 1)) { next = header.next; for (nextIndex=0; nextIndex<index; nextIndex++) next = next.next; } else { next = header; for (nextIndex=size; nextIndex>index; nextIndex--) next = next.previous; } }

现在,知道有多慢了吧?一个for循环,从0知道到index,也就是说LZ的程序如果用LinkedList做for循环调get(int index)方法的话,算法复杂度为O(n*n)!

然而,LinkedList的Iterator却是个好东西。它的next为:
Java code
    
    
public E next() { checkForComodification(); if (nextIndex == size) throw new NoSuchElementException(); lastReturned = next; next = next.next; nextIndex++; return lastReturned.element; }


简单吧?就一个next = next.next,全搞定!链表就是这个好,顺序遍历的时候很快,其实我觉得要比上面那个ArrayList的get(return elementData[index])要快。C里面也许数组挺快,但是Java里面,这个elementData是个Object数组,要求offset应该不是就一个乘法加一个加法那么简单吧?就算是一个乘法加一个加法,链表LinkedList就一个next的赋值(next是Entry)应该更快。

 

Iterator为什么产生?

ArrayList 和 LinkedList 是两个区别很大的集合, 没必要一起比嘛

Iterator 是集合提供的一个通用接口, 用来遍历集合元素的。在Collection下的集合都可以使用这个接口来遍历

提醒一下:用Iterator 迭代, 不是一样用了循环的嘛。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值