返回

Java 8 从容遍历集合,告别 ConcurrentModificationException 困扰

后端

Java 8 集合遍历和元素删除的并发修改问题

简介

在多线程编程中,当多个线程同时访问共享资源(如集合)时,可能会出现并发修改问题。在 Java 中,集合类默认情况下不是线程安全的,这意味着如果一个线程正在遍历集合,而另一个线程同时修改它,则会引发 ConcurrentModificationException 异常。

Java 8 解决并发修改问题的正确方法

为了避免 ConcurrentModificationException 异常,Java 8 提供了以下遍历集合并删除元素的正确方法:

1. 使用 Iterator.remove() 方法

Iterator.remove() 方法允许你在遍历集合时删除当前元素。但是,只能在调用 next() 方法后才能调用 remove() 方法,否则会引发 IllegalStateException 异常。

示例代码:

import java.util.ArrayList;
import java.util.Iterator;

public class IteratorRemoveExample {

    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Orange");
        fruits.add("Banana");

        Iterator<String> iterator = fruits.iterator();
        while (iterator.hasNext()) {
            String fruit = iterator.next();
            if (fruit.equals("Orange")) {
                iterator.remove();
            }
        }

        System.out.println(fruits); // 输出:[Apple, Banana]
    }
}

2. 使用 List.removeIf() 方法

List.removeIf() 方法允许你删除集合中满足特定条件的所有元素。它接受一个 Predicate 对象作为参数,该对象判断一个元素是否满足条件。

示例代码:

import java.util.ArrayList;

public class ListRemoveIfExample {

    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Orange");
        fruits.add("Banana");

        fruits.removeIf(fruit -> fruit.equals("Orange"));

        System.out.println(fruits); // 输出:[Apple, Banana]
    }
}

3. 使用 Stream.filter() 方法

Stream.filter() 方法允许你过滤掉集合中不满足特定条件的所有元素。它接受一个 Predicate 对象作为参数,该对象判断一个元素是否满足条件。

示例代码:

import java.util.ArrayList;
import java.util.stream.Collectors;

public class StreamFilterExample {

    public static void main(String[] args) {
        ArrayList<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Orange");
        fruits.add("Banana");

        List<String> filteredFruits = fruits.stream()
                .filter(fruit -> !fruit.equals("Orange"))
                .collect(Collectors.toList());

        System.out.println(filteredFruits); // 输出:[Apple, Banana]
    }
}

结论

通过使用 Iterator.remove(), List.removeIf(), 或 Stream.filter() 方法,你可以避免在 Java 8 中遍历集合并删除元素时出现并发修改问题。这些方法提供了安全且有效的方式来修改集合,而不会引发异常。

常见问题解答

  1. 为什么集合在 Java 中默认情况下不是线程安全的?

这是因为线程安全需要实现额外的同步机制,这会增加开销并降低性能。

  1. 什么时候会引发 ConcurrentModificationException 异常?

当一个线程正在遍历集合时,另一个线程修改了集合。

  1. 如何解决 ConcurrentModificationException 异常?

使用 Iterator.remove(), List.removeIf(), 或 Stream.filter() 方法遍历集合并删除元素。

  1. 哪种方法最适合遍历集合并删除元素?

这取决于特定场景。Iterator.remove() 最简单,而 Stream.filter() 允许你使用流操作进行更复杂的过滤。

  1. 如何防止在多线程环境中发生并发修改?

使用同步机制,如锁或并发集合类,以确保一次只有一个线程访问集合。