【HashMap】遍历读和遍历删除

【HashMap】遍历读和遍历删除

  • 【一】遍历读HashMap
    • 【1】方法一:for循环
    • 【2】方法二:迭代器
    • 【3】方法三:keySet()迭代
    • 【4】方法四:entrySet()迭代
    • 【5】方法五:stream流遍历以及lambda表达式遍历
  • 【二】遍历删除
    • 【1】迭代器遍历删除
    • 【2】为什么不用迭代器是不安全的?
    • 【3】为什么阿里巴巴禁止在foreach里进行集合(List、Map)元素的remove/add操作?

【一】遍历读HashMap

创建一个Map集合

Map<String,String> map=new HashMap<String,String>();  
    map.put("username", "qq");  
    map.put("passWord", "123");  
    map.put("userID", "1");  
    map.put("email", "[email protected]");

【1】方法一:for循环

for ( Map.Entry<String, String> entry : map.entrySet() ){  
        System.out.println ( entry.getKey()+"--->"+entry.getValue() );  
}

【2】方法二:迭代器

System.out.println("通过iterator遍历所有的value,但是不能遍历key");
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()){
    Map.Entry<String, String> next = iterator.next();
    System.out.println("key="+next.getKey()+"value="+next.getValue());
}

【3】方法三:keySet()迭代

System.out.println("通过map.keyset进行遍历key和value");
for (String key:map.keySet()) {
    System.out.println("key=  "+key+"   and value=  "+map.get(key));
}

【4】方法四:entrySet()迭代

System.out.println("通过Map.entrySet;")
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String>entry:entries){
    String value = entry.getValue();
    String key = entry.getKey();
    System.out.println("key="+key+"value="+value);
}

【5】方法五:stream流遍历以及lambda表达式遍历

HashMap<String, Integer> map1 = new HashMap<>();
map1.put("小明", 1);
map1.put("小红", 2);
map1.put("小张", 3);

//stream流遍历
map1.entrySet().stream().forEach((Map.Entry<String, Integer> entry) -> {
    System.out.print("key = " + entry.getKey());
    System.out.println(", value = " + entry.getValue());
});

但是在idea编译器中,编译器会给出警告,提示说该写法可以简化,简化后的写法和lambda表达式一致:

map1.forEach((key, value) -> {
    System.out.print("key = " + key);
    System.out.println(", value = " + value);
});

【二】遍历删除

【1】迭代器遍历删除

可以使用迭代器来遍历HashMap并删除元素。以下是一个示例代码:

HashMap<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);

Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<String, Integer> entry = iterator.next();
    if (entry.getValue() == 2) {
        iterator.remove();
    }
}

System.out.println(map);

通过使用迭代器的remove()方法,可以安全地从集合中删除元素。

【2】为什么不用迭代器是不安全的?

hashmap不用迭代器遍历删除是不安全的,是因为在使用迭代器遍历一个集合时,如果直接调用集合的remove方法删除元素,会导致迭代器内部的modCount字段与实际集合的modCount字段不一致。modCount字段是用来记录集合被修改的次数,当两者不一致时,迭代器会检测到该集合被并发修改的情况,并抛出ConcurrentModificationException异常。而使用迭代器的remove方法删除元素,则会更新modCount字段,保证一致性。

其他的包括【ForEach 循环方式、Lambda 表达式、Stream 方式】都不能保证数据安全

(1)迭代器 Iterator 方式,在迭代器 Iterator 中循环删除数据是安全的

public class HashMapSevenTest {

    public static void main(String[] args) {
        Map<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1, "Java");
        hashMap.put(2, "JDK");
        hashMap.put(3, "Spring Framework");
        hashMap.put(4, "MyBatis framework");
        hashMap.put(5, "Java中文社群");

        Iterator<Map.Entry<Integer, String>> iterator = hashMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Integer, String> entry = iterator.next();
            if (entry.getKey() == 1) {
                // 删除
                System.out.println("删除掉的Key为:" + entry.getKey());
                iterator.remove();
            } else {
                System.out.println("Map集合中剩余的Key为:" + entry.getKey());
            }
        }
    }
}

(2)ForEach 循环方式,在 ForEach 循环中删除数据是不安全的

public class HashMapEightTest {

    public static void main(String[] args) {
        Map<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1, "Java");
        hashMap.put(2, "JDK");
        hashMap.put(3, "Spring Framework");
        hashMap.put(4, "MyBatis framework");
        hashMap.put(5, "Java中文社群");

        for (Map.Entry<Integer, String> entry : hashMap.entrySet()) {
            if (entry.getKey() == 1) {
                // 删除
                System.out.println("删除掉的Key为:" + entry.getKey());
                hashMap.remove(entry.getKey());
            } else {
                System.out.println("Map集合中剩余的Key为:" + entry.getKey());
            }
        }
    }
}

(3)Lambda 表达式,在 Lambda 表达式循环中删除数据是不安全的

public class HashMapNineTest {

    public static void main(String[] args) {
        Map<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1, "Java");
        hashMap.put(2, "JDK");
        hashMap.put(3, "Spring Framework");
        hashMap.put(4, "MyBatis framework");
        hashMap.put(5, "Java中文社群");

        hashMap.keySet().removeIf(key -> key == 1);
        hashMap.forEach((key, value) -> {
            if (key == 1) {
                System.out.println("删除掉的Key为:" + key);
            } else {
                System.out.println("Map集合中剩余的Key为:" + key);
            }
        });
    }
}

(4)Stream 方式,在 Stream 循环中删除数据是不安全的

public class HashMapTenTest {

    public static void main(String[] args) {
        Map<Integer, String> hashMap = new HashMap<>();
        hashMap.put(1, "Java");
        hashMap.put(2, "JDK");
        hashMap.put(3, "Spring Framework");
        hashMap.put(4, "MyBatis framework");
        hashMap.put(5, "Java中文社群");

        hashMap.entrySet().stream().filter(m -> 1 != m.getKey()).forEach((entry) -> {
            if (entry.getKey() == 1) {
                System.out.println("删除掉的Key为:" + entry.getKey());
                hashMap.remove(entry.getKey());
            } else {
                System.out.println("Map集合中剩余的Key为:" + entry.getKey());
            }
        });
    }
}

(5)总结
1-不能在 ForEach 循环遍历中使用集合(List、Map) map.remove() 来删除数据,这是非安全的操作方式
2-可以使用迭代器 Iterator 的 iterator.remove() 的方法来删除数据,这是安全的删除集合的方式
3-可以使用 Lambda 中的 removeIf 来提前删除数据,或者是使用 Stream 中的 filter 过滤掉要删除的数据进行循环,这样都是安全的

【3】为什么阿里巴巴禁止在foreach里进行集合(List、Map)元素的remove/add操作?

foreach增强循环是依赖了 while 循环和 Iterator 实现的,起到和普通for循环一样的效果,但是在foreach遍历删除List或Map时,如果有重复的值【11,11,12,13】,遍历删除11的时候,只会删除第一个11,第二个11不会删除。

原因如下:
删除了第一个 11 后,集合里的元素个数减 1,后面的元素都往前移了 1 位,此时,第二个 11 已经移到了原索引下标 index = 1 的位置,而此时 i 马 上 i++ 了,list.get(i) 获得的是数据 12 。同时 list.size() 的值也在减小。

原数据:									11, 11, 12, 13, 14, 15, 16
原下标:									0	1	2	3	4	5	6

执行list.remove(0)删除第一个 11 后数据:		11, 12, 13, 14, 15, 16
执行list.remove(0)删除第一个 11 后下标:		0	1	2	3	4	5	

当list.remove(0)执行完后,在执行i++,而此时list.get(i)=12

你可能感兴趣的:(java,开发语言)