• list.remove的使用分析


    场景描述

    在做需求中,有很多情况会出现 对一个list遍历并过滤掉其中特定的数据 这种场景 。但是按照平常的使用方式,发现报错了。

    public static void main(String[] args) {
    String str1 = new String("abcde");
    String str2 = new String("abcde");
    String str3 = new String("abcde");
    String str4 = new String("abcde");
    String str5 = new String("abcde");
    List list = new ArrayList();
    list.add(str1);
    list.add(str2);
    list.add(str3);
    list.add(str4);
    list.add(str5);

    System.out.println("list.size()=" + list.size());
    for (int i = 0; i < list.size(); i++) {
    if (((String) list.get(i)).startsWith("abcde")) {
    list.remove(i);
    }
    }
    System.out.println("after remove:list.size()=" + list.size());
    }

      运行结果不是:

      list.size()=5

      after remove:list.size()=0

      居然是:

      list.size()=5

      after remove:list.size()=2

    原因:List每remove掉一个元素以后,后面的元素都会向前移动,此时如果执行i=i+1,则刚刚移过来的元素没有被读取。

    源码分析

    查看arrayList源码如下

        public E remove(int index); //执行删除指定位置的元素的功能
        public boolean remove(Object o)  //执行删除指定元素的功能
    

      remove(int index)在删除指定index位置时有以下3步

      • 先获取指定位置的元素用于返回值
      • 将指定位置以后的每个元素向前挪一位覆盖
      • 将数据最后一位 元素置空并将size减1
        public E remove(int index) {
    	RangeCheck(index);
    
    	modCount++;
    	E oldValue = (E) elementData[index];
    
    	int numMoved = size - index - 1;
    	if (numMoved > 0)
    	    System.arraycopy(elementData, index+1, elementData, index,
    			     numMoved);
    	elementData[--size] = null; // Let gc do its work
    
    	return oldValue;
        }

    remove(Object o)  

      判断object o 是否为null 如果为null 用 ==来判断,如果不为null 用 equals来判断引用是否相同

      从第一个找到即删除并返回

        public boolean remove(Object o) {
    	if (o == null) {
                for (int index = 0; index < size; index++)
    		if (elementData[index] == null) {
    		    fastRemove(index);
    		    return true;
    		}
    	} else {
    	    for (int index = 0; index < size; index++)
    		if (o.equals(elementData[index])) {
    		    fastRemove(index);
    		    return true;
    		}
            }
    	return false;
        }
    
        /*
         * Private remove method that skips bounds checking and does not
         * return the value removed.
         */
        private void fastRemove(int index) {
            modCount++;
            int numMoved = size - index - 1;
            if (numMoved > 0)
                System.arraycopy(elementData, index+1, elementData, index,
                                 numMoved);
            elementData[--size] = null; // Let gc do its work
        }
    

     

    删除 List 中的元素会产生两个问题:

    1. 删除元素后 List 的元素数量会发生变化;
    2. 对 List 进行删除操作可能会产生并发问题;

     

    解决方案

    倒过来遍历

      1.倒过来遍历list

      for (int i = list.size()-1; i > =0; i--) {

      if (((String) list.get(i)).startsWith("abcde")) {

      list.remove(i);

      }

      }

      2.每移除一个元素以后再把i移回来

      for (int i = 0; i < list.size(); i++) {

      if (((String) list.get(i)).startsWith("abcde")) {

      list.remove(i);

      i=i-1;

      }

      }

      3.使用iterator.remove()方法删除

      for (Iterator it = list.iterator(); it.hasNext();) {

      String str = (String)it.next();

      if (str.equals("chengang")){

      it.remove();

      }

      }

  • 相关阅读:
    分布式存储
    存储知识学习
    洛谷 P1003 铺地毯 (C/C++, JAVA)
    多线程面试题系列3_生产者消费者模式的两种实现方法
    多线程面试题系列2_监视线程的简单实现
    多线程面试题系列1_数组多线程分解
    《深度学习》阅读笔记1
    素数在两种常见情况下的标准最优算法
    dfs与dp算法之关系与经典入门例题
    百度之星资格赛2018B题-子串查询
  • 原文地址:https://www.cnblogs.com/shoshana-kong/p/9260155.html
Copyright © 2020-2023  润新知