HashMap的遍历

关于HashMap的遍历

近几日面试让手写HashMap的遍历,虽然依稀记得,奈何模糊了。
原文地址
共七种遍历方式:

  1. 使用迭代器(Iterator)EntrySet 的方式进行遍历;
  2. 使用迭代器(Iterator)KeySet 的方式进行遍历;
  3. 使用 For Each EntrySet 的方式进行遍历;
  4. 使用 For Each KeySet 的方式进行遍历;
  5. 使用 Lambda 表达式的方式进行遍历;
  6. 使用 Streams API 单线程的方式进行遍历;
  7. 使用 Streams API 多线程的方式进行遍历。

第一种、使用ForEach EntrySet的方式

	/**
     * 使用Foreach EntrySet
     */
    public void Test1(){
        Map<Integer,Integer> map = new HashMap<>();
        map.put(1,1111);
        map.put(2,2222);
        for (Map.Entry<Integer,Integer> entry:map.entrySet()) {
            System.out.println("Key=>"+entry.getKey());
            System.out.println("Value=>"+entry.getValue());
        }
    }

第二种、使用迭代器EntrySet

	/**
     * 使用迭代器EntrySet
     */
    public void Test3(){
        Map<Integer,Integer> map = new HashMap<>();
        map.put(1,1111);
        map.put(2,2222);
        Iterator<Map.Entry<Integer,Integer>> entries = map.entrySet().iterator();
        while (entries.hasNext()){
            Map.Entry<Integer,Integer> entry = entries.next();
            System.out.println("Key=>"+entry.getKey());
            System.out.println("Value=>"+entry.getValue());
        }
    }

第三种、使用迭代器KeySet的方式

	/**
     * 迭代键值对的方式
     */
    public void Test2(){
        Map<Integer,Integer> map = new HashMap<>();
        map.put(1,1111);
        map.put(2,2222);
        Iterator<Integer> iterator = map.keySet().iterator();
        while (iterator.hasNext()){
            Integer key = iterator.next();
            Integer value = map.get(key);
            System.out.println("Key=>"+key);
            System.out.println("Value=>"+value);
        }
    }

第四种、使用ForEach KeySet的方式

	/**
     * 使用ForEach KeySet
     */
    public void Test4(){
        Map<Integer,Integer> map = new HashMap<>();
        map.put(1,1111);
        map.put(2,2222);
        for (Integer key:map.keySet()) {
            System.out.println("Key=>"+key);
            System.out.println("Value=>"+map.get(key));
        }
    }

第五种、使用Lambda表达式的方式

	/**
     * 使用Lambda表达式
     */
    public void Test5(){
        Map<Integer,Integer> map = new HashMap<>();
        map.put(1,1111);
        map.put(2,2222);
        map.forEach((key,value) ->{
            System.out.println("key=>"+key);
            System.out.println("value=>"+value);
        });
    }

第六种、使用Streams API单线程的方式

 /**
     * Stream API单线程
     */
    public void Test6(){
        Map<Integer,Integer> map = new HashMap<>();
        map.put(1,1111);
        map.put(2,2222);
        map.entrySet().parallelStream().forEach((entry) -> {
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        });
    }

第七种、使用Streams API多线程的方式

/**
     * Streams API多线程
     */
    public void Test7(){
        Map<Integer,Integer> map = new HashMap<>();
        map.put(1,1111);
        map.put(2,2222);
        map.entrySet().parallelStream().forEach((entry) -> {
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        });
    }

总结:

EntrySet 之所以比 KeySet 的性能高是因为,KeySet 在循环时使用了 map.get(key),而 map.get(key) 相当于又遍历了一遍 Map 集合去查询 key 所对应的值。为什么要用“又”这个词?那是因为在使用迭代器或者 for 循环时,其实已经遍历了一遍 Map 集合了,因此再使用 map.get(key) 查询时,相当于遍历了两遍。
而 EntrySet 只遍历了一遍 Map 集合,之后通过代码“Entry entry = iterator.next()”把对象的 key 和 value 值都放入到了 Entry 对象中,因此再获取 key 和 value 值时就无需再遍历 Map 集合,只需要从 Entry 对象中取值就可以了。
所以,EntrySet 的性能比 KeySet 的性能高出了一倍,因为 KeySet 相当于循环了两遍 Map 集合,而 EntrySet 只循环了一遍。

我们不能在遍历中使用集合 map.remove() 来删除数据,这是非安全的操作方式,但我们可以使用迭代器的 iterator.remove() 的方法来删除数据,这是安全的删除集合的方式。同样的我们也可以使用 Lambda 中的 removeIf 来提前删除数据,或者是使用 Stream 中的 filter 过滤掉要删除的数据进行循环,这样都是安全的,当然我们也可以在 for 循环前删除数据在遍历也是线程安全的。

如果从性能方面考虑,我们应该尽量使用 lambda 或者是 entrySet 来遍历 Map 集合。尽量使用 entrySet 来遍历 HashMap,这样既安全又高效。

你可能感兴趣的:(知识点)