设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间23 现在时间23 缓存数据 别怀疑自己,别改变自己。别在意别人怎么想,大胆去追求自己想要的。

别怀疑自己,别改变自己。别在意别人怎么想,大胆去追求自己想要的。

查看: 1286|回复: 3

java中List移除元素的四种方式

[复制链接]

  离线 

TA的专栏

  • 打卡等级:热心大叔
  • 打卡总天数:219
  • 打卡月天数:0
  • 打卡总奖励:3305
  • 最近打卡:2025-04-04 00:23:53
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
422
主题
385
精华
0
金钱
4532
积分
849
注册时间
2023-1-22
最后登录
2025-5-31

发表于 2024-9-26 20:57:10 | 显示全部楼层 |阅读模式
目录
  • 四种方式:
    • 1.Iterator 迭代器
    • 2.倒序遍历
    • 3.正序遍历
    • 4.Stream流操作(JDK 1.8 +)
  • 问题:
    • 1.为什么不能使用forEach
    • 2.为什么forEach 删除倒数第二元素不会出现异常
    • 3 普通正序 for 循环为什么要 i –
    • 4 为什么倒序for 循环可以

四种方式:

  • 方式一,使用 Iterator ,顺序向下,如果找到元素,则使用 remove 方法进行移除。
  • 方式二,倒序遍历 List ,如果找到元素,则使用 remove 方法进行移除。
  • 方式三,正序遍历 List ,如果找到元素,则使用 remove 方法进行移除,然后进行索引 “自减”。
  • 方式四,使用jdk1.8新增的Stream流操作

1.Iterator 迭代器

  1. @Test
  2. public void fun9(){
  3. List<String> list = new ArrayList<>();
  4. list.add("赵云");
  5. list.add("黄忠");
  6. list.add("马超");
  7. list.add("关羽");
  8. list.add("张飞");
  9. // 获取迭代器
  10. Iterator<String> it = list.iterator();
  11. while(it.hasNext()){
  12. String str = it.next();
  13. if("关羽".equals(str)){
  14. it.remove();
  15. }
  16. }
  17. System.out.println(list);
  18. }
复制代码

2.倒序遍历

  1. @Test
  2. public void fun10(){
  3. List<String> list = new ArrayList<>();
  4. list.add("赵云");
  5. list.add("黄忠");
  6. list.add("马超");
  7. list.add("关羽");
  8. list.add("张飞");
  9. for (int i = list.size() - 1; i > 0; i--) {
  10. if("关羽".equals(list.get(i))){
  11. list.remove(i);
  12. }
  13. }
  14. System.out.println(list);
  15. }
复制代码

3.正序遍历

  1. @Test
  2. public void fun11(){
  3. List<String> list = new ArrayList<>();
  4. list.add("赵云");
  5. list.add("黄忠");
  6. list.add("马超");
  7. list.add("关羽");
  8. list.add("张飞");
  9. for (int i = 0; i < list.size(); i++) {
  10. if("关羽".equals(list.get(i))){
  11. list.remove(i);
  12. i--;
  13. }
  14. }
  15. System.out.println(list);
  16. }
复制代码

4.Stream流操作(JDK 1.8 +)

  1. @Test
  2. public void fun8(){
  3. List<String> list = new ArrayList<>();
  4. list.add("赵云");
  5. list.add("黄忠");
  6. list.add("马超");
  7. list.add("关羽");
  8. list.add("张飞");
  9. // 筛选出不是“关羽” 的集合
  10. list = list.stream().filter(e -> !"关羽".equals(e)).collect(Collectors.toList());
  11. System.out.println("method4|list=" + list);
  12. }
复制代码

问题:

1.为什么不能使用forEach

  1. @Test
  2. public void fun5(){
  3. List<String> list = new ArrayList<>();
  4. list.add("赵云");
  5. list.add("黄忠");
  6. list.add("马超");
  7. list.add("关羽");
  8. list.add("张飞");
  9. for (String str :list) {
  10. if ("张飞".equals(str)){
  11. list.remove(str);
  12. }
  13. }
  14. System.out.println(list);
  15. }
复制代码

1.png

原因:

foreach方式遍历元素的时候,是生成iterator,然后使用iterator遍历。在生成iterator的时候,会保存一个expectedModCount参数,这个是生成iterator的时候List中修改元素的次数。如果你在遍历过程中删除元素,List中modCount就会变化,如果这个modCount和exceptedModCount不一致,就会抛出异常。这个是为了安全的考虑。如果使用iterator遍历过程中,使用List修改了元素,可能会出现不正常的现象。如果使用iterator的remove方法则会正常,因为iterator的remove方法会在内部调用List的remove方法,但是会修改excepedModCount的值,因此会正常运行。

2.为什么forEach 删除倒数第二元素不会出现异常

  1. @Test
  2. public void fun12() {
  3. List<String> list = new ArrayList<>();
  4. list.add("赵云");
  5. list.add("黄忠");
  6. list.add("马超");
  7. list.add("关羽");
  8. list.add("张飞");
  9. for (String str:list) {
  10. if("关羽".equals(str)){
  11. list.remove(str);
  12. }
  13. System.out.println(str);
  14. }
  15. }
复制代码

2.png

仔细观察发现集合最后一个元素(“张飞”)并没有被遍历出来,因为当我们移除倒数第二个元素(“关羽”)时 cursor(游标)为 4 ,list 中size 属性的值会发生变化(5 - 1 = 4)变为 4,所以下面代码返回 false ,也就不会继续向下遍历。这也是能够正常执行的原因,因为如果继续遍历就会出现问题1 中的情况,在进行checkForComodification() 时,因为 modCount 发生了变化,而expectedModCount 并没有发生变化,所以会出现 ConcurrentModificationException异常。

  1. public void remove() {
  2. if (lastRet < 0)
  3. throw new IllegalStateException();
  4. checkForComodification();
  5. try {
  6. ArrayList.this.remove(lastRet);
  7. cursor = lastRet;
  8. lastRet = -1;
  9. expectedModCount = modCount;
  10. } catch (IndexOutOfBoundsException ex) {
  11. throw new ConcurrentModificationException();
  12. }
  13. }
复制代码
  1. public boolean hasNext() {
  2. return cursor != size;
  3. }
复制代码
  1. public E next() {
  2. checkForComodification();
  3. int i = cursor;
  4. if (i >= size)
  5. throw new NoSuchElementException();
  6. Object[] elementData = ArrayList.this.elementData;
  7. if (i >= elementData.length)
  8. throw new ConcurrentModificationException();
  9. cursor = i + 1;
  10. return (E) elementData[lastRet = i];
  11. }
复制代码
  1. final void checkForComodification() {
  2. if (modCount != expectedModCount)
  3. throw new ConcurrentModificationException();
  4. }
复制代码

3 普通正序 for 循环为什么要 i –

因为遍历过程中进行remove 操作时,该位置后面的元素会挤到前面来,这时候会发生一种情况就是原来元素的位置会被他后面的元素取代,而该位置已经遍历过了,所以该元素不会背遍历。 所以要进行 i-- 操作从该位置重新遍历。

  1. @Test
  2. public void fun11(){
  3. List<String> list = new ArrayList<>();
  4. list.add("赵云");
  5. list.add("黄忠");
  6. list.add("马超");
  7. list.add("关羽");
  8. list.add("张飞");
  9. for (int i = 0; i < list.size(); i++) {
  10. System.out.println(list.get(i));
  11. if("关羽".equals(list.get(i))){
  12. list.remove(i);
  13. }
  14. }
  15. System.out.println(list);
  16. }
复制代码

就是下面的情况 “张飞” 不见了…

3.png

4 为什么倒序for 循环可以

当我们倒序遍历元素的时候,无论删除元素之后的元素怎么移动,之前的元素对应的索引(index)是不会发生变化的,所以在删除元素的时候不会发生问题。

到此这篇关于java中List移除元素的四种方式的文章就介绍到这了,更多相关java List移除元素内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
18
积分
16
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2024-12-24 09:38:47 | 显示全部楼层
路过,支持一下
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
21
积分
22
注册时间
2022-12-25
最后登录
2022-12-25

发表于 2025-2-9 18:18:48 | 显示全部楼层
感谢楼主分享。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~

  离线 

TA的专栏

  • 打卡等级:即来则安
  • 打卡总天数:27
  • 打卡月天数:0
  • 打卡总奖励:321
  • 最近打卡:2025-03-14 19:55:51
等级头衔

等級:晓枫资讯-列兵

在线时间
0 小时

积分成就
威望
0
贡献
0
主题
0
精华
0
金钱
369
积分
56
注册时间
2023-1-15
最后登录
2025-3-14

发表于 2025-4-18 12:58:34 | 显示全部楼层
感谢楼主,顶。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1楼
2楼
3楼
4楼

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表