当前位置:主页 > java教程 > Java ArrayList删除指定位置元素

Java ArrayList实现删除指定位置的元素

发布:2023-03-03 13:00:01 59


给寻找编程代码教程的朋友们精选了相关的编程文章,网友龚景曜根据主题投稿了本篇教程内容,涉及到Java、ArrayList删除指定位置元素、Java、ArrayList删除元素、Java、ArrayList删除指定元素、Java ArrayList删除指定位置元素相关内容,已被869网友关注,相关难点技巧可以阅读下方的电子资料。

Java ArrayList删除指定位置元素

目标:list中有0到39共40个元素,删除其中索引是10、20、30的元素

方案一:使用普通for循环从前往后遍历再删除

//初始化List列表
List<String> list = new ArrayList<>();
for (int i = 0; i < 40; i++) {
    list.add("element" + i);
}

首先当我们删除第10位元素时,List会将后面的元素向前补位,之后再查第10位元素就会输出第11位元素

for (int i = 0; i < list.size(); i++) {
    if (i == 10) {
        list.remove(i);
    }
}
System.out.println(list.get(10));

输出:

element11

那么删除了一个元素以后,后面需要删除的元素位置就向前提1位

/**
 * 如果明确需要删除元素的位置
 * 那么可以这样,每删除一个元素后就把下一个要删除元素的位置减1
 * 注意这么做有个需要注意的点,那就是每次删除完节点后遍历指针i需要减一,这样在删除两个临近节点时才不会出现问题
 * 比如要删除10和11
 */
for (int i = 0; i < list.size(); i++) {
    if (i == 10) {
        list.remove(i);
        i--;
    }
    if (i == 19) {
        list.remove(i);
        i--;
    }
    if (i == 28) {
        list.remove(i);
        i--;
    }
}

System.out.println(list.contains("element10"));
System.out.println(list.contains("element20"));
System.out.println(list.contains("element30"));

输出:

 false
 false
 false

当然我们可以用一个数组或列表从小到大存储需要删除的位置,然后再for循环中进行运算和取值

方案二:使用普通for循环从后往前遍历再删除

从后向前遍历的好处是我们不需要再像方案一一样每删除一个元素都需要去考虑后面元素向前补位的问题

for (int i = list.size() - 1; i >= 0; i--) {
    if (i == 30) {
        list.remove(i);
    }
    if (i == 20) {
        list.remove(i);
    }
    if (i == 10) {
        list.remove(i);
    }
}
System.out.println(list.contains("element10"));
System.out.println(list.contains("element20"));
System.out.println(list.contains("element30"));

输出:

 false
 false
 false

从后向前,即使后面进行元素进行向前补位操作也不会影响前面需要删除的元素

这里也可以用一个数组或列表存储需要删除的元素,从大到小排列,取出一个删除一个

方案三:使用迭代器删除

Iterator<String> iterator = list.iterator();
int i = 0;
while (iterator.hasNext()) {
    String next = iterator.next();
    if (i == 10) {
        iterator.remove();
    }
    i++;
}
System.out.println(list.get(10));
System.out.println(list.contains("element10"));

输出:

element11
false

在迭代器中维护一个数字i标识遍历的位置

如果我们在迭代器中继续删除另外20和30位置元素

Iterator<String> iterator = list.iterator();
int i = 0;
while (iterator.hasNext()) {
    String next = iterator.next();
    if (i == 10) {
        iterator.remove();
    }
    if (i == 20) {
        iterator.remove();
    }
    if (i == 30) {
        iterator.remove();
    }
    i++;
}
System.out.println(list.get(10));
System.out.println(list.contains("element10"));
System.out.println(list.get(20));
System.out.println(list.contains("element20"));
System.out.println(list.get(30));
System.out.println(list.contains("element30"));

输出:

element11
false
element22
false
element33
false

首先我们在迭代过程中指定的是删除10、20、30三个位置的元素,可以看到输出contains时都是false表示正确删除,但是最终输出列表的值发现对应索引位置已经进行了补位。

我们debug分析一下为什么

先简单介绍一下Iterator和Iterable

Iterable是一个迭代接口,实现了这个接口代表该类可以迭代

可以看到我们的集合Collection接口就是它的子类

它有一个主要方法:

// 返回一个实现了Iterator接口的对象,我们也是用这个对象去进行迭代
Iterator<T> iterator();

Iterator,它主要有三个方法:

// 返回是否还有下一个元素
boolean hasNext();
// 返回下一个元素
E next();
// 删除该元素
default void remove() {
    throw new UnsupportedOperationException("remove");
}

每个不同的集合类都会有不同的Iterator接口实现,在ArrayList中使用了一个内部类来实现

private class Itr implements Iterator<E> {
    int cursor;       // index of next element to return
    int lastRet = -1; // index of last element returned; -1 if no such
    int expectedModCount = modCount;

    Itr() {}
}

我们通过list.iterator()拿到的就是这个内部类的对象实例,这个类中有两个字段cursor和lastRet,这两个字段就是我们能在迭代器中正确删除对应位置的元素的关键。

有关expectedModCount和modCount的问题后面会补充,我们先不用关注

cursor初始化是0 lastRet初始化是-1

分析next和remove方法的源码

/**
* 可以先不关注这两个Exception
* 每次调用next() cursor都会+1 而lastRet就会变成之前cursor的值
* cursor初始化是0
* lastRet初始化是-1
* 调用一次以后  cursor是1 lastRet变成0
**/
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];
}

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

    try {
        // 调用本身的remove方法
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}

关键是这个remove方法对cursor和lastRet的修改

假如正在删除第10个元素

执行remove方法前cursor应该是11,lastRet是10

执行了以后lastRet变成了-1,cursor变成了10

下次执行next()方法返回的元素其实还是elementData[10]也就是List补位后正确的下一个元素,cursor变成了11,lastRet是10

总结:使用迭代器遍历时ArrayList会用lastRet和cursor两个变量来维护当前遍历的元素索引和下一次需要遍历元素的索引,通过这两个变量就可以实现迭代中正确的删除某个位置的元素。

到此这篇关于Java ArrayList实现删除指定位置的元素的文章就介绍到这了,更多相关Java ArrayList删除指定位置元素内容请搜索码农之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持码农之家!


参考资料

相关文章

  • Java单例模式和多例模式的知识点讲解

    发布:2020-03-08

    这篇文章主要介绍了Java单例模式和多例模式,结合实例形式分析了java单例模式与多例模式的定义及使用技巧,需要的朋友可以参考下


  • Java Set接口及常用实现类总结

    发布:2023-03-02

    Collection的另一个子接口就是Set,他并没有我们List常用,并且自身也没有一些额外的方法,全是继承自Collection中的,因此我们还是简单总结一下,包括他的常用实现类HashSet、LinkedHashSet、TreeSet的总结


  • Java Autowired注解深入分析

    发布:2023-04-18

    @Autowired注解是Spring中非常重要且常见的,接下来就简要的介绍一下它的用法。@Autowired默认是通过set方法,按照类型自动装配JavaBean,set方法可省略不写,它主要是修饰在成员变量上


  • java开发接口吞吐量提升10多倍技巧

    发布:2023-03-05

    这篇文章主要为大家介绍了java开发技巧之接口吞吐量提升10多倍的方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪


  • 详解Java如何判断ResultSet结果集是否为空

    发布:2023-04-07

    ResultSet 表示 select 语句的查询结果集。这篇文章主要为大家详细介绍了Java如何判断ResultSet结果集是否为空,感兴趣的可以了解一下


  • 使用java -jar修改SpringBoot中application.properties的配置项

    发布:2023-04-02

    这篇文章主要介绍了使用java -jar修改SpringBoot中application.properties的配置项问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教


  • Javascript实现信息滚动效果的方法

    发布:2020-03-20

    这篇文章主要为大家详细介绍了Javascript实现信息滚动效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下


  • 详解Java Selenium中的键盘控制操作

    发布:2023-03-02

    这篇文章主要为大家介绍了如何使用java代码利用Selenium 控制浏览器中需要用到的键盘操作。文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下


网友讨论