zoukankan      html  css  js  c++  java
  • 关于List比较好玩的操作

    本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/9347357

        作为Java大家庭中的集合类框架,List应该是平时开发中最常用的,可能有这种需求,当集合中的某些元素符合一定条件时,想要删除这个元素。如:

    [java] view plain copy
     
     print?
    1. public class ListTest {  
    2.     public static void main(String[] args) {  
    3.        List<Integer> intList = new ArrayList<Integer>();  
    4.        Collections.addAll(intList, 12356);  
    5.        // for循环优化写法,只获取一次长度  
    6.        for(int i = 0, size = intList.size(); i < size; i++) {  
    7.            Integer value = intList.get(i);  
    8.            // 符合条件,删除元素  
    9.            if(value == 3 || value == 5) {  
    10.               intList.remove(i);  
    11.            }  
    12.        }  
    13.        System.out.println(intList);  
    14.     }  
    15. }  

          执行后,会抛出IndexOutOfBoundsException,因为集合中存在符合条件的元素,删除后,集合长度动态改变,由于长度只获取一次,发生越界,所以,去掉for循环优化,如:

    [java] view plain copy
     
     print?
    1. public class ListTest {  
    2.     public static void main(String[] args) {  
    3.        List<Integer> intList = new ArrayList<Integer>();  
    4.        Collections.addAll(intList, 12356);  
    5.        for(int i = 0; i < intList.size(); i++) {  
    6.            Integer value = intList.get(i);  
    7.            // 符合条件,删除元素  
    8.            if(value == 3 || value == 5) {  
    9.               intList.remove(i);  
    10.            }  
    11.        }  
    12.        System.out.println(intList);  
    13.     }  
    14. }  

          输出:[1, 2, 5, 6],漏掉了5这个元素,当i=2的时候,值为3,删除后,后面的元素往前补一位,这时i=3的时候,值为6,跳过了5,这样也不行,随后想到了用for循环增强,不显示的操作下标,直接操作对象,如:

    [java] view plain copy
     
     print?
    1. public class ListTest {  
    2.     public static void main(String[] args) {  
    3.        List<Integer> intList = new ArrayList<Integer>();  
    4.        Collections.addAll(intList, 12356);  
    5.        for(Integer value : intList) {  
    6.            // 符合条件,删除元素  
    7.            if(value == 3 || value == 5) {  
    8.               intList.remove(value);  
    9.            }  
    10.        }  
    11.        System.out.println(intList);  
    12.     }  
    13. }  

          执行后,会抛出ConcurrentModificationException,字面意思是并发修改异常。异常跟踪信息如下:

     

    Exception inthread "main" java.util.ConcurrentModificationException

             atjava.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)

             at java.util.AbstractList$Itr.next(AbstractList.java:420)

             at ListTest.main(ListTest.java:13)

           可以大概看出是执行到AbstractList中内部类Itr的checkForComodification方法抛出的异常,至于为什么出现异常,这里可以大概解释一下。集合遍历是使用Iterator, Iterator是工作在一个独立的线程中,并且拥有一个互斥锁。Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast原则 Iterator 会马上抛出java.util.ConcurrentModificationException 异常。所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。

           而要解决这个问题,可以使用Iterator的remove方法,该方法会删除当前迭代对象的同时,维护索引的一致性。如:

    [java] view plain copy
     
     print?
    1. public class ListTest {  
    2.     public static void main(String[] args) {  
    3.        List<Integer> intList = new ArrayList<Integer>();  
    4.        Collections.addAll(intList, 12356);  
    5.        Iterator<Integer> it = intList.iterator();  
    6.        while(it.hasNext()) {  
    7.            Integer value = it.next();  
    8.            if(value == 3 || value == 5) {  
    9.               it.remove();  
    10.            }  
    11.        }  
    12.        System.out.println(intList);  
    13.     }  
    14. }  

          输出正确结果:[1, 2, 6]。

     

           不使用迭代器的解决方案就是,自己维护索引,删除一个元素后,索引-1,如:

    [java] view plain copy
     
     print?
    1. public class ListTest {  
    2.     public static void main(String[] args) {  
    3.        List<Integer> intList = new ArrayList<Integer>();  
    4.        Collections.addAll(intList, 12356);  
    5.        for(int i = 0; i < intList.size(); i++) {  
    6.            Integer value = intList.get(i);  
    7.            if(value == 3 || value == 5) {  
    8.               intList.remove(i);  
    9.               i--;  
    10.            }  
    11.        }  
    12.         System.out.println(intList);  
    13.     }  
    14. }  

          输出正确结果:[1, 2, 6]。

     

     

           还有种取巧的方式是从最后一个元素开始遍历,符合条件的删除,如:

    [java] view plain copy
     
     print?
    1. public class ListTest {  
    2.     public static void main(String[] args) {  
    3.        List<Integer> intList = new ArrayList<Integer>();  
    4.        Collections.addAll(intList, 12356);  
    5.        for(int i = intList.size() - 1; i >= 0; i--) {  
    6.            Integer value = intList.get(i);  
    7.            if(value == 3 || value == 5) {  
    8.               intList.remove(i);  
    9.            }  
    10.        }  
    11.         System.out.println(intList);  
    12.     }  
    13. }  

          输出正确结果:[1, 2, 6]。

     

           最后,Java集合类框架真是大大方便了开发,不用自己去维护数组,随时担心着越界等问题。当然List的实现类对插入、删除的效率不太一样,这取决于其实现的数据结构,是选择删除,还是选择新建个集合,这里就不做讨论了。

  • 相关阅读:
    品优购(IDEA版)-第二天
    品优购(IDEA版)-第一天
    GitHub客户端Desktop的安装和使用总结
    Android开发10:传感器器及地图相关应用
    Android开发9:网络访问&Web服务开发
    Android开发8:数据存储(二)——SQLite数据库和ContentProvider的使用
    Android开发7:简单的数据存储(使用SharedPreferences)和文件操作
    Android开发6:Service的使用(简单音乐播放器的实现)
    归纳整理一些工作学习中发现的不错的网站、博客地址等(转载)
    Android Studio安装配置、环境搭建详细步骤及基本使用
  • 原文地址:https://www.cnblogs.com/chase1/p/7182394.html
Copyright © 2011-2022 走看看