循环删除 List 中的元素

循环删除 List 中的元素,这个问题是有需要的注意点的,如果是个新手,确实会遇到一点麻烦

比如有以下这个 List:

public List<String> initList = Arrays.asList("张三", "李四", "周一", "刘四", "李强", "李白");

1、普通 for 循环删除(不可靠)

/**
 * 普通 for 循环删除
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove1() {
    List<String> list = new ArrayList(initList);
    for (int i = 0; i < list.size(); i++) {
        String str = list.get(i);
        if (str.startsWith("李")) {
            list.remove(i);
        }
    }
    System.out.println(list);
}

问题就出在 list.size(),因为 list.size() 和 i 都是动态变化的,i 的值一直在累加,list.size() 一直在减少,所以 list 就会早早结束了循环。

所以这种方式虽然不会报错,但存在隐患,并且不容易被察觉,不建议使用

2、普通 for 循环提取变量删除(抛异常)

/**
 * 普通 for 循环删除(size提出变量)
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove2() {
    List<String> list = new ArrayList(initList);
    int size = list.size();
    for (int i = 0; i < size; i++) {
        String str = list.get(i);
        if (str.startsWith("李")) {
            list.remove(i);
        }
    }
    System.out.println(list);
}

直接干下标溢出异常了。这里也很明显,因为 size 变量是固定的,但 list 的实际大小是不断减小的,而 i 的大小是不断累加的,一旦 i >= list 的实际大小肯定就异常了。

3、普通 for 循环倒序删除(可靠)

/**
 * 普通 for 循环倒序删除
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove3() {
    List<String> list = new ArrayList(initList);
    for (int i = list.size() - 1; i > 0; i--) {
        String str = list.get(i);
        if (str.startsWith("李")) {
            list.remove(i);
        }
    }
    System.out.println(list);
}

输出结果:[张三, 周一, 刘四]

结果输出正常,这种删除方式就算把 list.size() 提出变量也是 OK 的,因为循环中只用到了一次。

4、增强 for 循环删除(抛异常)

/**
 * 增强 for 循环删除
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove3() {
    List<String> list = new ArrayList(initList);
    for (String element : list) {
        if (element.startsWith("李")) {
            list.remove(element);
        }
    }
    System.out.println(list);
}

又抛异常了。不过这次的异常和上面的下标异常不太一样,这次是:java.util.ConcurrentModificationException 这个是集合操作中很常见的异常之一,即并发修改异常!

5、迭代器循环迭代器删除(可靠)

/**
 * 迭代器循环删除(iterator.remove)
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove4() {
    List<String> list = new ArrayList(initList);
    for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
        String str = iterator.next();
        if (str.contains("李")) {
            iterator.remove();
        }
    }
    System.out.println(list);
}

输出结果:[张三, 周一, 刘四]

6、迭代器循环集合删除(抛异常)

/**
 * 迭代器循环删除(list.remove)
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove5() {
    List<String> list = new ArrayList(initList);
    for (Iterator<String> ite = list.iterator(); ite.hasNext(); ) {
        String str = ite.next();
        if (str.contains("李")) {
            list.remove(str);
        }
    }
    System.out.println(list);
}

又是那个并发修改异常,这个示例虽然使用了 Iterator 循环,但删除的时候却使用了 list.remove 方法,同样是有问题的,注意了,千万别用错了。

7、集合 forEach 方法循环删除(抛异常)

/**
 * list.forEach 删除
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove6() {
    List<String> list = new ArrayList(initList);
    list.forEach((e) -> {
        if (e.contains("李")) {
            list.remove(e);
        }
    });
    System.out.println(list);
}

又是那个并发修改异常。

8、stream filter 过滤(可靠)

/**
 * stream filter 过滤
 * @author: 栈长
 * @from: 公众号Java技术栈
 */
@Test
public void remove7() {
    List<String> list = new ArrayList(initList);
    list = list.stream().filter(e -> !e.startsWith("李")).collect(Collectors.toList());
    System.out.println(list);
}

总结:

  • 普通 for 循环倒序删除(可靠)

  • 迭代器循环迭代器删除(可靠)

  • stream filter 过滤(可靠)

可靠、可行的方案也只有 3 种,正统的删除法也就 2 种,但也要注意别用错了方法。

感觉不错就点个赞吧!

猜你喜欢

转载自blog.csdn.net/qq_25462179/article/details/132322443