当前位置:   article > 正文

007Java集合011遍历集合元素并修改_set集合改值

set集合改值

注意:本文基于JDK1.8进行记录。

1 遍历Collection

对List和Set的遍历,有四种方式,下面以ArrayList为例进行说明。

1.1 普通for循环

使用普通for循环的遍历方式效率最高,尽量将循环无关的代码放置在集合外执行。

代码如下:

  1. for (int i = 0; i < list.size(); i++) {
  2.     System.out.println(i);
  3. }

如果要在普通for循环里对集合元素进行删除操作,可能会出现问题:

  1. public static void main(String[] args) {
  2.     List<Integer> list = new ArrayList<Integer>();
  3.     list.add(1);
  4.     list.add(2);
  5.     list.add(2);
  6.     list.add(4);
  7.     list.add(5);
  8.     for (int i = 0; i < list.size(); i++) {
  9.         if (list.get(i) == 2) {
  10.             list.remove(i);
  11.         }
  12.     }
  13.     System.out.println(list);
  14. }

运行结果如下:

[1, 2, 4, 5]

结果说明:

集合中有两个值为2的元素,但是在代码执行之后,值为2的元素并没有完全移除。

在第一次删除后,集合发生了改变,删除位置之后的所有元素都向前挪动了一个位置,删除位置上的元素由下一位置上的元素替代。

在下次遍历时,从删除位置后开始判断,跳过了删除位置上的元素,从而导致最后打印的结果和预期的不一致。

改进的办法是在删除之后设置索引减1,重新判断删除位置上的元素。

1.2 增强for循环

进一步精简了遍历的代码,底层使用迭代器。

代码如下:

  1. for (Integer i : list) {
  2.     System.out.println(i);
  3. }

如果在增强for循环里删除或者添加集合元素,那么一定会报异常:

  1. public static void main(String[] args) {
  2.     List<Integer> list = new ArrayList<Integer>();
  3.     list.add(1);
  4.     list.add(2);
  5.     list.add(2);
  6.     list.add(4);
  7.     list.add(5);
  8.     for (Integer i : list) {
  9.         if (i == 2) {
  10.             list.remove(i);
  11.         }
  12.     }
  13.     System.out.println(list);
  14. }

运行结果如下:

java.util.ConcurrentModificationException

结果说明:

抛出ConcurrentModificationException异常是由快速失败(fail-fast)机制引起的,该机制是为了避免在遍历集合时,对集合的结构进行修改。

快速失败机制使用modCount记录集合的修改次数,在删除时除了删除对应元素外,还会更新modCount。

增强for循环本质上是使用迭代器进行遍历,迭代器在初始化时会使用expectedModCount记录当时的modCount,遍历时会检查expectedModCount是否和modCount相同,如果不同就会抛出ConcurrentModificationException异常。

1.3 使用迭代器

代码如下:

  1. Iterator<Integer> iterator = list.iterator();
  2. while (iterator.hasNext()) {
  3.     System.out.println(iterator.next());
  4. }

如果在迭代器中使用集合提供的删除或添加方法,同样会报错:

  1. public static void main(String[] args) {
  2.     List<Integer> list = new ArrayList<Integer>();
  3.     list.add(1);
  4.     list.add(2);
  5.     list.add(2);
  6.     list.add(4);
  7.     list.add(5);
  8.     Iterator<Integer> iterator = list.iterator();
  9.     while (iterator.hasNext()) {
  10.         if (iterator.next() == 2) {
  11.             list.add(6);
  12.         }
  13.     }
  14.     System.out.println(list);
  15. }

运行结果如下:

java.util.ConcurrentModificationException

结果说明:

这里抛出异常的原因和增强for循环一样,同样是因为快速失败机制。

解决办法是在迭代器中删除或添加元素时,使用迭代器提供的删除或添加方法,不要使用集合提供的删除或添加方法。

需要注意的是,普通迭代器中只提供了删除方法,在集合迭代器中还提供了添加和修改方法。

1.4 使用集合迭代器

代码如下:

  1. ListIterator<Integer> iterator = list.listIterator();
  2. while (iterator.hasNext()) {
  3.     System.out.println(iterator.next());
  4. }

在迭代器中使用迭代器提供的删除或添加方法:

  1. public static void main(String[] args) {
  2.     List<Integer> list = new ArrayList<Integer>();
  3.     list.add(1);
  4.     list.add(2);
  5.     list.add(2);
  6.     list.add(4);
  7.     list.add(5);
  8.     ListIterator<Integer> iterator = list.listIterator();
  9.     while (iterator.hasNext()) {
  10.         if (iterator.next() == 2) {
  11.             iterator.remove();
  12.         }
  13.     }
  14.     System.out.println(list);
  15. }

运行结果如下:

[1, 4, 5]

结果说明:

迭代器提供的方法同时维护了modCount和expectedModCount,所以不会产生快速失败。

1.5 使用forEach方法

forEach方法是JDK1.8新增的方法,需要配合Lambda表达式使用,代码如下:

list.forEach(i -> System.out.println(i));

使用forEach方法遍历:

  1. public static void main(String[] args) {
  2.     List<Integer> list = new ArrayList<Integer>();
  3.     list.add(1);
  4.     list.add(2);
  5.     list.add(2);
  6.     list.add(4);
  7.     list.add(5);
  8.     list.forEach(i -> {
  9.         if (i == 2) {
  10.             list.remove(i);
  11.         }
  12.     });
  13.     System.out.println(list);
  14. }

运行结果如下:

java.util.ConcurrentModificationException

结果说明:

这里抛出异常的原因也是因为快速失败机制。

2 遍历Map

对Map的遍历,有四种方式,下面以HashMap为例进行说明。

2.1 通过keySet()方法遍历key和value

通过keySet()方法获取到map的所有key值,遍历key值的集合,获取对应的value值。代码如下:

  1. for (Integer i : map.keySet()) {
  2.     System.out.println(i + " >>> " + map.get(i));
  3. }

运行结果如下:

  1. 0 >>> 000
  2. 1 >>> 111
  3. 2 >>> 222
  4. 3 >>> 333
  5. 4 >>> 444

在遍历的时候是可以修改的,但是不能添加和删除,否则会抛出ConcurrentModificationException异常,代码如下:

  1. for (Integer i : map.keySet()) {
  2.     System.out.println(i + " >>> " + map.get(i));
  3.     if (map.get(i) == "222") {
  4.         map.put(i, "999");
  5.     }
  6. }

运行结果如下:

  1. 0 >>> 000
  2. 1 >>> 111
  3. 2 >>> 999
  4. 3 >>> 333
  5. 4 >>> 444

2.2 通过entrySet()方法遍历key和value

这种方式同样支持修改,但不支持添加和删除,这种方式的效率最高,代码如下:

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

2.3 通过entrySet()方法获取迭代器遍历key和value

这种方式同样支持修改,但不支持添加和删除,代码如下:

  1. Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
  2. while (iterator.hasNext()) {
  3.     Map.Entry<Integer, String> entry = iterator.next();
  4.     System.out.println(entry.getKey() + " >>> " + entry.getValue());
  5. }

2.4 通过values()方法遍历所有的value

这种方式只能遍历value,不能遍历key,代码如下:

  1. for (String value : map.values()) {
  2.     System.out.println(value);
  3. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/470417
推荐阅读
相关标签
  

闽ICP备14008679号