List移除元素

本文详细介绍了在Java中从List中移除元素的四种有效方法,包括使用Iterator、倒序遍历、正序遍历及Stream流操作,并解析了各种方法的原理与适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

List 移除某个元素

四种方式:

  • 方式一,使用 Iterator ,顺序向下,如果找到元素,则使用 remove 方法进行移除。
  • 方式二,倒序遍历 List ,如果找到元素,则使用 remove 方法进行移除。
  • 方式三,正序遍历 List ,如果找到元素,则使用 remove 方法进行移除,然后进行索引 “自减”。
  • 方式四,使用jdk1.8新增的Stream流操作
    1.Iterator 迭代器
	@Test
    public void fun9(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        // 获取迭代器
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String str = it.next();
            if("关羽".equals(str)){
                it.remove();
            }
        }
        System.out.println(list);
    }

2.倒序遍历

	@Test
    public void fun10(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (int i = list.size() - 1; i > 0; i--) {
            if("关羽".equals(list.get(i))){
                list.remove(i);
            }
        }
        System.out.println(list);
    }

3.正序遍历

 	@Test
    public void fun11(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (int i = 0; i < list.size(); i++) {
            if("关羽".equals(list.get(i))){
                list.remove(i);
                i--;
            }
        }
        System.out.println(list);
    }

4.Stream流操作(JDK 1.8 +)

	@Test
    public void fun8(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        // 筛选出不是“关羽” 的集合
        list = list.stream().filter(e -> !"关羽".equals(e)).collect(Collectors.toList());
        System.out.println("method4|list=" + list);

    }

问题:

1.为什么不能使用forEach

	@Test
    public void fun5(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (String str :list) {
            if ("张飞".equals(str)){
                list.remove(str);
            }
        }
        System.out.println(list);
    }

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

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

 	@Test
    public void fun12() {
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (String str:list) {
            if("关羽".equals(str)){
                list.remove(str);
            }
            System.out.println(str);
        }
    }

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

public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
 public boolean hasNext() {
            return cursor != size;
        }
public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

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

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

	@Test
    public void fun11(){
        List<String> list = new ArrayList<>();
        list.add("赵云");
        list.add("黄忠");
        list.add("马超");
        list.add("关羽");
        list.add("张飞");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
            if("关羽".equals(list.get(i))){
                list.remove(i);
            }
        }
        System.out.println(list);
    }

就是下面的情况 “张飞” 不见了…
在这里插入图片描述

4 为什么倒序for 循环可以

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

### 如何在Java中从List移除元素 在Java中,`ArrayList` 是 `List` 接口的一个实现类,提供了多种方法来删除列表中的元素。以下是几种常见的操作方式: #### 使用 `remove(Object o)` 方法 此方法用于通过对象本身来移除第一个匹配项。如果找到并成功移除该对象,则返回 `true`;否则返回 `false`[^1]。 ```java import java.util.ArrayList; import java.util.List; public class RemoveExample { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("A"); list.add("B"); list.add("C"); boolean isRemoved = list.remove("B"); // 移除指定的对象 "B" System.out.println(list); // 输出: [A, C] System.out.println(isRemoved); // 输出: true } } ``` #### 使用 `remove(int index)` 方法 当需要基于索引来移除某个特定位置上的元素时可以使用这个方法。它会将位于给定索引处的元素移除,并使后续元素向前移动一位以填补空缺的位置[^2]。 ```java import java.util.ArrayList; import java.util.List; public class IndexRemoveExample { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); numbers.add(10); numbers.add(20); numbers.add(30); int removedValue = numbers.remove(1); // 移除第二个元素 System.out.println(numbers); // 输出: [10, 30] System.out.println(removedValue); // 输出: 20 } } ``` #### 删除重复元素 为了清除集合内的所有副本只保留唯一实例,可以通过转换成 `HashSet` 来达成目标因为哈希集不允许存在任何两个相等成员之间共享相同键值的情况发生从而达到去重效果后再变回原来的类型继续使用. ```java import java.util.*; public class DuplicateRemoval { public static void main(String[] args){ List<String> originalList = Arrays.asList("apple", "banana", "orange", "apple", "grape"); Set<String> setWithoutDuplicates = new HashSet<>(originalList); List<String> newListWithNoDupes = new ArrayList<>(setWithoutDuplicates); System.out.println(newListWithNoDupes); // 可能输出顺序不同如:[banana, grape, orange, apple] } } ``` #### 利用迭代器安全地遍历期间修改容器结构 为了避免并发修改异常(ConcurrentModificationException),应该采用显式的 Iterator 对象来进行循环访问的同时执行增删动作: ```java import java.util.*; public class SafeIterationDeletion{ public static void main(String []args){ List<Integer> nums=new LinkedList<>(); Collections.addAll(nums,1,2,3,4,5,-9,-8,-7); Iterator<Integer> iterator=nums.iterator(); while(iterator.hasNext()){ Integer num=iterator.next(); if(num<0){ iterator.remove();//仅在此调用有效不会引发错误 } } System.out.println(nums);//打印结果应该是正整数序列[1, 2, 3, 4, 5] } } ``` ---
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值