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;
}