最安全的删除方式是使用迭代器的remove,或者使用removeIf

181 阅读3分钟
  1. removeByIndex方法示范了通过索引删除元素的方式。

  2. removeByValue方法示范了通过元素的值删除的方式。

  3. forEachRemoveWrong方法展示了在foreach循环中直接调用list.remove会出现的问题。 由于列表大小在循环时发生了变化,会跳过之后的元素导致删除不完整。

  4. forEachRemoveRight方法示范了在foreach循环中使用迭代器的remove方法可以安全删除元素。 因为它在每次next()后才执行remove,避免了并发修改问题。

  5. forEachRemoveRight2方法展示了使用List的removeIf方法可以通过条件predicate删除元素,较为简洁。

public class ListRemoveApplication {

    public static void main(String[] args) {
//        removeByIndex(4);
//        removeByValue(Integer.valueOf(4));

//        forEachRemoveWrong();
        forEachRemoveRight();
        forEachRemoveRight2();
    }

    //removeByIndex方法示范了通过索引删除元素的方式
    private static void removeByIndex(int index) {
        List<Integer> list =
                IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toCollection(ArrayList::new));
        System.out.println(list.remove(index));
        System.out.println(list);
    }

    //removeByValue方法示范了通过元素的值删除的方式
    private static void removeByValue(Integer index) {
        /**
         * 这行代码使用IntStream生成了一个1到10的Integer列表,具体分析:
         *
         * 1. IntStream.rangeClosed(1, 10)生成一个1到10的int流
         *
         * 2. .boxed()对这个原始int流进行装箱,转换为Integer流
         *
         * 3. .collect(Collectors.toCollection(ArrayList::new))将Integer流收集到一个ArrayList中
         *
         * 4. ArrayList::new是一个方法引用,表示创建ArrayList
         *
         * 5. 所以Collectors.toCollection(ArrayList::new)表示创建一个ArrayList来收集流中的元素
         *
         * 6. 综上,将1到10的int流,装箱为Integer流,再收集到ArrayList中
         *
         * 7. 最后将其赋值给变量list,所以list的值就是一个包含1到10的Integer对象的ArrayList
         *
         * 所以这行代码使用了流式操作的方式高效地生成了一个ArrayList,省去了传统方式的for循环添加元素等代码。
         *
         * 利用IntStream、boxed、collect这些Stream API,可以通过函数式的链式调用,非常简洁地生成所需数据结构。
         *
         * 这种链式流操作风格可以大大提高代码的简洁性和可读性。
         */
        List<Integer> list =
                IntStream.rangeClosed(1, 10).boxed().collect(Collectors.toCollection(ArrayList::new));
        System.out.println(list.remove(index));
        System.out.println(list);
    }

    //forEachRemoveWrong方法展示了在foreach循环中直接调用list.remove会出现的问题。
    //由于列表大小在循环时发生了变化,会跳过之后的元素导致删除不完整。
    private static void forEachRemoveWrong() {
        //mapToObj(String::valueOf) 将int映射为String,valueOf方法可以把整数转换为对应的字符串
        //得到一个1到10的整数对应的Stream<String>
        //collect(Collectors.toCollection(ArrayList::new)) 将String流收集到ArrayList
        //最终得到一个包含"1"到"10"的ArrayList存放字符串
        List<String> list =
                IntStream.rangeClosed(1, 10).mapToObj(String::valueOf).collect(Collectors.toCollection(ArrayList::new));
        try {
            for (String i : list) {
                if ("2".equals(i)) {
                    list.remove(i);
                }
            }
        }catch (ConcurrentModificationException e){
            System.out.println(list);
        }

//        System.out.println(list);
    }

    //forEachRemoveRight方法示范了在foreach循环中使用迭代器的remove方法可以安全删除元素。
    //因为它在每次next()后才执行remove,避免了并发修改问题
    private static void forEachRemoveRight() {
        List<String> list =
                IntStream.rangeClosed(1, 10).mapToObj(String::valueOf).collect(Collectors.toCollection(ArrayList::new));
        for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
            String next = iterator.next();
            if ("2".equals(next)) {
                iterator.remove();
            }
        }
        System.out.println(list);

    }

    //forEachRemoveRight2方法展示了使用List的removeIf方法可以通过条件predicate删除元素,较为简洁
    private static void forEachRemoveRight2() {
        List<String> list =
                IntStream.rangeClosed(1, 10).mapToObj(String::valueOf).collect(Collectors.toCollection(ArrayList::new));
        list.removeIf(item -> item.equals("2"));
        list.removeIf("3"::equals);
        System.out.println(list);
    }
}

学习:Java 业务开发常见错误 100 例学习笔记