ConcurrentModiciationException在迭代时将元素添加到列表时

时间:2019-01-06 13:06:22

标签: java android

我的适配器中有此代码,其中显示了学校列表。还有一个搜索过滤器。只要搜索过滤器有一个值,列表就必须显示包含搜索过滤器字母的学校。这是我的代码-

public boolean refreshAdapter() {
        List<School> schools = cache().getSchools();
        if (schoolList != null && !schoolList.isEmpty()) {
            schoolList .clear();
        }

        schoolList = schools;

        for (School school: schoolList) {

            String name = school.getName();
            String address = vehicle.getAddress();

            if (name.contains(searchFilterText)|| address.contains(searchFilterText)) {
                schoolList.add(school);
            }
        }
        notifyDataSetChanged();
        if (schoolList!= null) {
            return schoolList.isEmpty();
        }
        return false;
    }

如何在没有并发修改异常的情况下运行此代码?我尝试使用ListIterator,但没有帮助我

3 个答案:

答案 0 :(得分:2)

ConcurrentModificationException的产生是因为schoolList列表在迭代该列表的过程中被修改。一种替代方法是改为迭代schools列表,并对schoolList进行添加,从而将要迭代的列表与要修改的列表分开:

schoolList = new ArrayList<>();

for (School school: schools) {

    String name = school.getName();
    String address = vehicle.getAddress();

    if (name.contains(searchFilterText)|| address.contains(searchFilterText)) {
        schoolList.add(school);
    }
}

另一种替代方法(使用JDK 8或更高版本)是过滤schools列表并将结果捕获到schoolList中:

schoolList = schools.stream()
    .filter(school -> school.getName().contains(searchFilterText) || school.getAddress().contains(searchFilterText))
    .collect(Collectors.toList());

根据代码的当前状态,您似乎将重新添加元素到schoolList,因为它已经包含了这些元素,因此为什么要遍历它们。上面的代码示例生成仅包含匹配元素的列表。如果希望将匹配元素重新添加到schoolList中,如原始问题所示,则可以在第一个示例中替换以下行

schoolList = new ArrayList<>();

使用

schoolList = new ArrayList<>(school);

这将创建school列表的副本,并将其存储在迭代开始之前的schoolList中。

如果这是预期的行为,请小心,因为这可能会导致无限循环。例如,在原始问题中,如果未引发ConcurrentModificationException,则如果添加与条件(School)相匹配的name.contains(searchFilterText)|| address.contains(searchFilterText)对象,则稍后也会对其进行迭代。反过来会匹配条件,然后重新添加。此过程将无限重复。例如,假设schoolList中唯一的元素与条件匹配,则以下是每次迭代后schoolList中包含的结果:

迭代0:

matching school A    <-- Current element of iteration
matching school A    <-- [newly added element]

迭代1:

matching school A
matching school A    <-- Current element of iteration
matching school A    <-- [newly added element]

迭代2:

matching school A
matching school A
matching school A    <-- Current element of iteration
matching school A    <-- [newly added element]

无限等等。

答案 1 :(得分:0)

您得到ConcurrentModificationException-s的原因是您在遍历列表的同时向其添加内容。通常,这是禁止的,因为通过迭代添加内容会造成混淆。在某些情况下,程序员希望迭代迭代最近添加的项,有时则不需要。因此,java迫使我们明确地执行上述任一操作。

您可以使用存储要添加到列表中的项目的临时列表进行修复。

第1步:找到要添加的项目。

List<School> tempSchoolList = new ArrayList<>(); // this is the new list

// most of the things below comes from the original code
schoolList = schools;

for (School school: schoolList) {

    String name = school.getName();
    String address = vehicle.getAddress();
    if (name.contains(searchFilterText)|| address.contains(searchFilterText)) {
        tempSchoolList.add(school); // add the new list to the temp school list
    }
}

步骤2:将临时列表中的项目添加到原始文件中

schoolList.addAll(tempSchoolList);

答案 2 :(得分:0)

请注意,发生此异常的原因是您在迭代集合时不得向集合中添加元素。您是否对schoolsshoolList感到困惑?为他们提供更合理的名称会很有帮助!

要正确执行此操作,您必须构建一个新的过滤列表(我评论了更改的行)

    // this is the new filtered list
    schoolList = new ArrayList<>();

    // iterate the original list
    for (School school: schools) {

        String name = school.getName();
        String address = vehicle.getAddress();

        if (name.contains(searchFilterText)|| address.contains(searchFilterText)) {
             // add it to filtered list
            schoolList.add(school);
        }
    }