开发者社区> 问答> 正文

JAVA中如何在遍历的同时删除 ArrayList 中的元素?

JAVA中如何在遍历的同时删除 ArrayList 中的元素?

展开
收起
vncamyi27xznk 2021-11-14 23:09:22 559 0
1 条回答
写回答
取消 提交回答
  • "1、 直接使用普通 for 循环进行操作 我们说不能在 foreach 中进行,但是使用普通的 for 循环还是可以的,因为普通 for 循环并没有用到 Iterator 的遍历,所以压根就没有进行 fail-fast 的检验。 console.log(List<String> userNames = new ArrayList<String>() {{ add(""Hollis""); add(""hollis""); add(""HollisChuang""); add(""H""); }}; for (int i = 0; i < 1; i++) { if (userNames.get(i).equals(""Hollis"")) { userNames.remove(i); } } System.out.println(userNames);) 这种方案其实存在一个问题,那就是 remove 操作会改变 List 中元素的下标,可能存在漏删的情况。 2、 直接使用 Iterator 进行操作 除了直接使用普通 for 循环以外,我们还可以直接使用 Iterator 提供的 remove 方法。 console.log(List userNames = new ArrayList () {{ add(""Hollis""); add(""hollis""); add(""HollisChuang""); add(""H""); }}; Iterator iterator = userNames.iterator(); while (iterator.hasNext()) { if (iterator.next().equals(""Hollis"")) { iterator.remove(); } } System.out.println(userNames);) 如 果 直 接 使 用 I t e r a t o r 提 供 的 r e m o v e 方 法 , 那 么 就 可 以 修 改 到 expectedModCount 的值。那么就不会再抛出异常了。 3、 使用 Java 8 中提供的 filter 过滤 Java 8 中可以把集合转换成流,对于流有一种 filter 操作, 可以对原始 Stream 进行某项测试,通过测试的元素被留下来生成一个新 Stream。 console.log(List<String> userNames = new ArrayList<String>() {{ add(""Hollis""); add(""hollis""); add(""HollisChuang""); add(""H""); }}; userNames = userNames.stream().filter(userName -> !userName.equals(""Hol lis"")).collect(Collectors.toList()); System.out.println(userNames);) 4、 使用增强 for 循环其实也可以 如果,我们非常确定在一个集合中,某个即将删除的元素只包含一个的话, 比如对 Set 进行操作,那么其实也是可以使用增强 for 循环的,只要在删除之后,立刻结束循环体,不要再继续进行遍历就可以了,也就是说不让代码执行到下一次的 next 方法。 console.log(List<String> userNames = new ArrayList<String>() {{ add(""Hollis""); add(""hollis""); add(""HollisChuang""); add(""H""); }}; for (String userName : userNames) { if (userName.equals(""Hollis"")) { userNames.remove(userName); break; } } System.out.println(userNames);) 5、 直接使用 fail-safe 的集合类 在 Java 中,除了一些普通的集合类以外,还有一些采用了 fail-safe 机制的集合类。这样的集合容器在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。 由于迭代时是对原集合的拷贝进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发 ConcurrentModificationException。 console.log(ConcurrentLinkedDeque<String> userNames = new ConcurrentLinkedDeque<String> () {{ add(""Hollis""); add(""hollis""); add(""HollisChuang""); add(""H""); }}; for (String userName : userNames) { if (userName.equals(""Hollis"")) { userNames.remove(); } }) 基于拷贝内容的优点是避免了 ConcurrentModificationException,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。 java.util.concurrent 包下的容器都是安全失败,可以在多线程下并发使用,并发修改。

    资料来源:《Java工程师成神之路(基础篇)》,链接:https://developer.aliyun.com/topic/download?id=923"

    2021-11-15 23:19:31
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
Spring Cloud Alibaba - 重新定义 Java Cloud-Native 立即下载
The Reactive Cloud Native Arch 立即下载
JAVA开发手册1.5.0 立即下载