版权声明:转载请标明出处 https://blog.csdn.net/weixin_36759405/article/details/83904452
问题一可以看我之前写的博客List 循环遍历中删除元素问题一。
问题二主要讲的是博主在今天的开发中遇到的一个问题,先来看下是什么问题让博主继上次问题后又写了问题二。
问题一中讲到通过Iterator的remove方法解决链表中循环删除元素的问题。来看下简单的代码:
public class ListTest {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if ("4".equals(s)) {
iterator.remove();
}
}
System.out.println("list:" + list);
}
}
输出:list:[1, 2, 3, 5],成功删除元素4。
但是这种解决方法中隐藏着一个坑。在今天和前端的联调过程中发现,我们一般从数据库查询多条数据时会返回List<?>,?表示具体的实体类,然后通过Iterator遍历List删除其中的元素,以下是类似的代码:
public class ListTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("1","2","3","4","5");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if ("4".equals(s)) {
iterator.remove();
}
}
System.out.println("list:" + list);
}
}
原本以为通过iterator.remove()方法能够成功删除元素,但是上述代码在控制台却报了这么一个错:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.remove(AbstractList.java:161)
at java.util.AbstractList$Itr.remove(AbstractList.java:374)
at list.ListTest.main(ListTest.java:22)
一开始感到很困惑,但是在经过自己debug之后终于发现了问题所在,debug下进入的第一个方法:
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
在执行到AbstractList.this.remove(lastRet);
时进入下一个方法:
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
/*... 其它方法略...*/
public E remove(int index) {
throw new UnsupportedOperationException();
}
}
原来此处的ArrayList是一个实现了AbstractList的内部类,并且没有覆盖add和remove方法,默认这2个方法是会直接报“UnsupportedOperationException”的。
知道问题原因后,解决方法也就明确了。
public class ListTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("1","2","3","4","5");
List<String> result= new ArrayList<>(list);
Iterator<String> iterator = result.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if ("4".equals(s)) {
iterator.remove();
}
}
System.out.println("list:" + result);
}
}
通过将list拷贝到一个新的ArrayList中即可解决问题二。
总结:在设计一个对外方法的时候,一点要谨慎处理集合和数组。因为你永远不知道传给你的集合是什么,也不知道是否会有对此集合有任何其他的不可控的操作。所以在使用客户端传递的集合对象时,最好拷贝一个新集合后再操作。