1 容易出现的问题:
1 package collectionDemo.list; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class ListDemo { 7 8 public static void main(String[] args) { 9 List<String> sList = new ArrayList<String>(); 10 sList.add("0"); 11 sList.add("1"); 12 sList.add("2"); 13 sList.add("3"); 14 sList.add("4"); 15 System.out.println(sList); 16 // 对list进行遍历,并按条件进行删除 17 for (int i = 0; i < sList.size(); i++) { 18 if (i == 1 || i == 2) { 19 sList.remove(i); 20 } 21 } 22 System.out.println(sList); 23 24 } 25 26 }
输出结果为:
[0, 1, 2, 3, 4]
[0, 2, 4]
乍一看代码,像是实现删除索引为1和2的元素。但执行结果却并非如此。在执行遍历集合删除元素时,当i==1时,集合remove掉索引为1(i)的元素,移除字符串1,此处是正常逻辑。但执行到i==2时,remove的却是字符串3。原因如下:
使用普通for循环遍历ArrayList时,是以索引为依据进行遍历的。在遍历过程中remove元素会导致索引的混乱。比如上例中,当remove(1)后,集合size将发生变化,元素将变少,字符串2所对应的索引将由2变为1,后边的字符串3和4依次类推索引变为2和3,执行下一次循环时,i++为2,此时remove的是字符串3,所以导致了上述结果。
2 解决方案1:
public class ListDemo { 7 8 public static void main(String[] args) { 9 List<String> sList = new ArrayList<String>(); 10 sList.add("0"); 11 sList.add("1"); 12 sList.add("2"); 13 sList.add("3"); 14 sList.add("4"); 15 System.out.println(sList); 16 // 对list进行遍历,并按条件进行删除 17 for (int i = 0; i < sList.size(); i++) { 18 if (i == 1 || i == 2) { 19 sList.remove(i); i--; 20 } 21 } 22 System.out.println(sList); 23 24 }
添加了删除元素后对下标i进行i--操作,保证下标不错乱。
3 解决方案2:
使用迭代器对集合进行遍历,并进行集合中元素的删除操作,如:
public class ListDemo { public static void main(String[] args) { List<String> sList = new ArrayList<String>(); sList.add("0"); sList.add("1"); sList.add("2"); sList.add("3"); sList.add("4"); System.out.println(sList); Iterator<String> iterator=sList.iterator(); while(iterator.hasNext()){ String item=iterator.next(); if(item.equals("1")){ iterator.remove(); //sList.remove(item);注释的用法是错误用法,迭代器中的迭代需使用迭代器进行删除操作,不能在使用集合的remove方法,此种用法会导致java.util.ConcurrentModificationException } } System.out.println(sList); } }
以上举例以list为例,同理在map集合中存在同样的问题,举一反三。
4 解决方案3(推荐),使用removeIf:
package collectionDemo; import java.util.ArrayList; import java.util.List; public class ListDmeo { public static void main(String[] args) { List<String> sList = new ArrayList<String>(); sList.add("0"); sList.add("1"); sList.add("2"); sList.add("3"); sList.add("4"); sList.removeIf(str-> str.equals("1")); System.out.println(sList); } }
打印结果:
[0, 2, 3, 4]
removeIf内部也是使用的迭代器进行的删除操作,源码如下:
default boolean removeIf(Predicate<? super E> filter) { Objects.requireNonNull(filter); boolean removed = false; final Iterator<E> each = iterator(); while (each.hasNext()) { if (filter.test(each.next())) { each.remove(); removed = true; } } return removed; }