• Java中删除元素方法你真的懂了吗?


    回顾最初接触的删除元素的方法(在线性表中的删除)

    删除方法:就是将要删除的后续元素前移,然后修改数组长度(下面代码是由后面向前遍历(逆遍历)):

    1. package ly.csdn.text;
    2. public class Sort1 {
    3. private static int size;//原始数组长度
    4. public static void main(String[] args) {
    5. //定义一个数组(线性表)
    6. int[] arr = {4513,323,2342,24,62,314,53,324};
    7. size = arr.length;//初始化原始数组长度
    8. //删除小于俩百的元素
    9. for(int i=size-1;i>=0;--i) {
    10. if(arr[i]<200) {
    11. delete(arr,i);
    12. --size;
    13. }
    14. }
    15. //输出删除后的序列
    16. for(int i=0;i
    17. System.out.print(arr[i] + " ");
    18. }
    19. }
    20. //删除索引为index的元素
    21. private static void delete(int[] arr,int index) {
    22. //后续元素前移
    23. for(int i=index;i1;++i) {
    24. arr[i] = arr[i+1];
    25. }
    26. }
    27. }

    (这是删除后序列元素)

    如果是由前面开始遍历呢?会有预期的结果吗?(以下是错误结果示范)

    1. package ly.csdn.text;
    2. public class Sort1 {
    3. private static int size;//原始数组长度
    4. public static void main(String[] args) {
    5. //定义一个数组(线性表)
    6. int[] arr = {4513,323,2342,24,62,314,53,324};
    7. size = arr.length;//原始数组长度初始化
    8. //删除小于俩百的元素
    9. for(int i=0;i
    10. if(arr[i]<200) {
    11. delete(arr,i);
    12. --size;
    13. }
    14. }
    15. //输出删除后的序列
    16. for(int i=0;i
    17. System.out.print(arr[i] + " ");
    18. }
    19. }
    20. //删除索引为index的元素
    21. private static void delete(int[] arr,int index) {
    22. //后续元素前移
    23. for(int i=index;i1;++i) {
    24. arr[i] = arr[i+1];
    25. }
    26. }
    27. }

    查看输出结果,我们发现62没有被删除成功,这是为什么呢? 

    这是因为删除24后,62被移动到了24这个位置,而 i 仍然在移动所以,错过了访问62的机会,导致没有删除成功。

    当然学了集合后,我们清楚可以直接调用方法库直接对元素进行删除(remove(int index)/remove(Object o)),但它真的是最安全,最快捷的删除方法吗?

    咱来看看源码它是怎么个实现的吧:

     上面那个remove咱不看(只是为了连贯就一起截过来了)咱看看 fastRemove方法。

    分析代码:

    newsize是定义删除元素后的新长度的(newSize = size - 1和上面线性表所写的 --size 差不多一个含义)

    当newSize == i呢就说明删除的元素是最后一个元素,直接退出了判断语句

    es[size = newSize] = null 也就是把原先最后一个元素置为空,也就是除去了

    它中间调用了System类中的一个方法arraycopy(Object src,int srcPos,Object dest,int destPos,int length)咱看这个方法参数名字也能猜中大概吧:就是把src对象数组索引从dest开始长为length的序列复制到dest索引从destPos的数组中。

    这里System.arraycopy(es,i+1,es,i,newSize-i)就是es从i+1开始长为newSize-i(和size-i+1等价,就是索引i后面那段序列)从索引 i 开始复制到es数组(自己本身,自己复制给自己)中去。

    对源码分析后发现了啥没?

    这不就是和线性表删除结果是一样的,只是它调用了方法库,使用方便了,既然是一样,那么使用它删除多个元素时候就要注意了不可以向前遍历(删除一个的话无所谓,啥方法都一样)。

    当我们顺序遍历删除的时候得注意点了,防止出错:

    1. package ly.csdn.text;
    2. import java.util. *;
    3. public class Sort1 {
    4. public static void main(String[] args) {
    5. //定义一个数组(线性表)
    6. List list = new ArrayList<>();
    7. //存入元素
    8. list.add(203);
    9. list.add(218);
    10. list.add(139);
    11. list.add(352);
    12. //删除小于俩百的元素
    13. for(int i=0;i
    14. if(list.get(i)<200) {
    15. list.remove(i);
    16. --i;//这里向前挪一位
    17. }
    18. }
    19. //输出删除后的序列
    20. for(int i=0;i
    21. System.out.print(list.get(i) + " ");
    22. }
    23. }

    (逆遍历删除是可以的不会出错)

    foreach遍历删除呢?

    答案是不可以用这个进行删除的。

    首先我们得搞清楚foreach遍历元素的时候,是生成iterator,然后用它进行遍历的。

    生成iterator,相对应的集合有个参数expectedModcound,这个参数会初始化为在生成iterator前修改该集合的次数,也就是会和List中的Modcound会相同(iterator接口中有检测expectModcound 和 Modcound是否相同的方法,如果不相同会抛出异常)当我们用foreach去遍历,然后用list去删除时,Modcound会随删除而改变,这时候expectModcound与Modcound不相同,那么会抛出异常。

    (当我们用foreach删除元素时候会抛出异常, 所以应避免使用它进行该操作)

    用线性表删除并不是很简洁。那有没有更好的删除方式呢?

    迭代器iterator遍历删除

    下面是《阿里巴巴泰山开发手册》上的一个点:

     下面是用iterator进行删除的代码:

    1. package ly.csdn.text;
    2. import java.util. *;
    3. public class Sort1 {
    4. public static void main(String[] args) {
    5. //定义一个数组(线性表)
    6. List list = new ArrayList<>();
    7. //存入元素
    8. list.add(203);
    9. list.add(218);
    10. list.add(139);
    11. list.add(120);
    12. list.add(352);
    13. //删除小于俩百的元素
    14. Iterator it = list.iterator();
    15. while(it.hasNext()) {
    16. Integer x = it.next();
    17. if(x<200)
    18. it.remove();
    19. }
    20. //输出删除后的序列【203,218,352】
    21. for(int i=0;i
    22. System.out.print(list.get(i) + " ");
    23. }
    24. }

    用iterator进行删除也要注意:不能同时进行俩次及俩次以上的删除(remove()),这和成员变量cursor(当前遍历的位置)和lastRet(上一次遍历的位置)有关,操作时是对cursor进行操作,操作完cursor会被设值为-1,如果还对它进行操作,那就会抛出数组越界异常,详细看这篇文档有对其的解释(源码分析):Java List用迭代器删除源码细节

    其他删除方法

    除了上述所写的,我们还可以用List接口中提供的removeAll(Collection c)方法。

    我们可以创建一个集合对象,里面存放要删除的元素,然后再用removeAll方法进行删除即可。

    如代码所示:

    1. package ly.csdn.text;
    2. import java.util. *;
    3. public class Sort1 {
    4. public static void main(String[] args) {
    5. //定义一个数组(线性表)
    6. List list = new ArrayList<>();
    7. //存入元素
    8. list.add(203);
    9. list.add(218);
    10. list.add(139);
    11. list.add(120);
    12. list.add(352);
    13. //删除小于俩百的元素
    14. List listDelete = new ArrayList<>();
    15. for(Integer x:list) {
    16. if(x<200)
    17. listDelete.add(x);
    18. }
    19. list.removeAll(listDelete);
    20. //输出删除后的序列【203,218,352】
    21. for(int i=0;i
    22. System.out.print(list.get(i) + " ");
    23. }
    24. }

    总结

    1. 叙述了用线性表删除式删除应该注意的点,如果要用记得 --i 或者采用逆遍历的思想;

    2. 叙述了为什么不能foreach遍历来删除元素

    3. 强烈建议用 iterator 迭代器的方式进行删除元素或遍历元素

    4. 用迭代器删除时不能一次性多次进行删除,原因和源码中成员变量cursor和lastRet有关

    5. 拓展了用removeAll集合方法进行删除

     

  • 相关阅读:
    vscode+makefile开发STM32---支持C++开发
    Java中,对象一定在堆中分配吗?
    会议OA之待开会议&所有会议
    [附源码]Python计算机毕业设计大学生项目众筹系统
    Python大数据之linux学习总结——day06_hive02
    MATLAB如何将k线图设置为经典红绿配色?
    JWT 实现登录认证 + Token 自动续期方案
    掌握电子邮件的未来:深入解析IMAP4的革命性特性与实践
    保障网络安全:IP代理识别API的作用与应用
    一图读懂k8s informer client-go
  • 原文地址:https://blog.csdn.net/qq_63691275/article/details/127093374