Java基础 List中元素的遍历删除

遍历删除List中元素时,有时会出现意想不到得错误

——使用普通for循环删除元素


	public static void main(String[] args)
	{  
	        List<Integer> list = new ArrayList<>();  
	        for (int i = 0; i < 5; i++)  
	            list.add(i);  
         
	        for (int i = 0; i < list.size(); i++) 
	        {  
               
	             list.remove(i);  

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

希望 通过list.remove(index)方式删除所有元素    但结果显示只删除了部分元素

Java基础 List中元素的遍历删除

删除元素后,会该变其它元素的index下标 以及整个list的Size大小 

 

Java基础 List中元素的遍历删除

——通过增强for循环删除元素

public static void main(String[] args)
{  
		List<Integer> list = new ArrayList<>();  
	        for (int i = 0; i < 5; i++)  
	            list.add(i);  
	        for (Integer num : list) 
	            if (num % 2 == 0) 
                   list.remove(num);  

}  

运行时直接出现  ConcurrentModificationException异常

Java基础 List中元素的遍历删除

原因分析: 增强for循环内部采用 Iterator迭代器进行遍历

 

fail-fast 机制是java集合(Collection)中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。例如:当某一个线程A通过iterator去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException异常,产生fail-fast事件。当方法检测到对象的并发修改,但不允许这种修改时就抛出该异常。同时需要注意的是,该异常不会始终指出对象已经由不同线程并发修改,如果单线程违反了规则,同样也有可能会抛出该异常。

Iterator是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator被创建之后会建立一个指向原来对象的单链索引表(副本),当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出java.util.ConcurrentModificationException异常。

 

——通过Iterator迭代器循环删除(正确做法)

public class List_test {
	public static void main(String[] args)
	{  
		List<Integer> list = new ArrayList<>();  
	        for (int i = 0; i < 5; i++)  
	            list.add(i);  
	        Iterator<Integer> it=list.iterator();
	        while(it.hasNext())
	        {
	        	if(it.next()%2==0)
	        		it.remove();
	        }
	        
	 }  
}  

Iterator迭代器可以认为是一个由头指针开始的访问指针,即使删除元素,依旧保持勾连状态,可以正确删除List中元素 

 

对于多线程中的线程安全的CopyOnWriteArrayList 

其Iterator只是原先数据的一个副本快照,所有不能采用Iterator迭代器遍历删除,而可以采用增强For循环(与普通ArrayList不同)

——正确做法

public class Main {  
    public static void main(String[] args) throws Exception {  
        List<Integer> list = new CopyOnWriteArrayList<>();  
        for (int i = 0; i < 5; i++)  
            list.add(i);  
        for (Integer num : list)  
            if (num % 2 == 0) {  
                list.remove(num);  
              
      
    }  
}