Java数据结构之迭代器

collection工具箱几乎为每一个集合类都提供了迭代器iterator供使用者对数据结构进行迭代访问;jdk 8下的用法如下:

 //keyset iterator
        Iterator keySelfIterator=map.keySet().iterator();
        while (keySelfIterator.hasNext())
        {
            Integer key=(Integer)keySelfIterator.next();
            String value=map.get(key);
        }
        //entryset iterator
        Iterator entrysetIterator=map.entrySet().iterator();
        while (entrysetIterator.hasNext())
        {
            Integer key=(Integer)entrysetIterator.next();
            String value=map.get(key);
        }

这样就可以顺序访问元素,为什么在这里要强调下jdk的版本呢,简单介绍下,在上古时代你是可以这样用的,

 for(Map.Entry<Integer, String> entry : map.entrySet()){
             Integer key = entry.getKey();
             if(key % 2 == 0){
                 System.out.println("To delete key " + key);
                 map.remove(key);
                 System.out.println("The key " + + key + " was deleted");
             }
        }

这里你会得到无情的报错ConcurrentModificationException;大家也很容易想到原因,map.remove元素的变化导致了异常,那么是什么样的原因导致了这个呢?本着给博客凑字数的心态我去查了其他博客和源码,
hashmap的remove

public V remove(Object key) {
    Entry<K,V> e = removeEntryForKey(key);
    return (e == null ? null : e.value);
}

hashmap.hashiterator的remove方法

public void remove() {
   if (current == null)
        throw new IllegalStateException();
   if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
   Object k = current.key;
   current = null;
   HashMap.this.removeEntryForKey(k);
   expectedModCount = modCount;
}

不知道有没有感受到赤果果的嘲讽,关键处expectedModCount = modCount;这里每次remove时,或者对map做put等操作时,mod跟expectedModCount都被做处理了,而hashmap并没有。

我们继续讲,那么keyset跟entryset用哪个好呢,以我目前的知识储备只能告诉你,用entryset,entryset,entryset.因为速度相差的实在是有点多;

  public static void main(String[] args) {

        Map map = new HashMap();

        initMap(map);

        keySetTravel(map);

        entrySetTravel(map);

    }





    private static void initMap(Map map) {

        for (int i = 0; i < 1000; i++) {

            map.put(i, new Point(0, i));

        }

    }



    public static void keySetTravel(Map map) {

        long startTime = System.currentTimeMillis();

        Set keySet = map.keySet();

        for (Integer key : keySet) {

            System.out.println(key + ":" + map.get(key));

        }

        System.out.println("keySetTravel:" + (System.currentTimeMillis() - startTime));

    }



有兴趣的可以跑跑,简单的很, 为什么差别这么大呢?这两种遍历方式代码几乎完全雷同,只是在获取Value对象的时候不一样。entrySet遍历方式获取Value对象是直接从Entry对象中直接获得,时间复杂度T(n)=o(1);keySet遍历获取Value对象则要从Map中重新获取,keySet遍历Map方式比entrySet遍历Map方式多了一次循环,多遍历了一次table,当Map的size越大时,遍历的效率差别就越大。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值