有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

我自己代码中的java ConcurrentModificationException


我认为我的解决方案与另一个问题的解决方案有误。它也被编辑过,所以看起来解决方案就是副本所指向的,但这显然没有解决我的问题,只是避免了出现异常(问题的表面)。由于我重新讨论这个问题的努力毫无用处,我已经开始了一个新的问题


我得到了一个ConcurrentModificationException,我无法解决这个问题。所以我从一个列表中删除了一系列元素,我得到了一个错误

这就是错误:

04-Nov-2016 15:49:50.488 SEVERE [http-nio-8080-exec-199] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [Faces Servlet] in context with path [/...] threw exception [java.util.ConcurrentModificationException] with root cause
 java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:886)
    at java.util.ArrayList$Itr.next(ArrayList.java:836)
    at com.ex.PersonController.removeGroup(...)
    at ....

Java代码:

public void removeGroup(int age) {
    if (person != null) {
        List<Person> friends = person.getFriends();
        List<Person> removeFriends = new ArrayList<>();
        if (friends != null) {
            for (Person p : friends) {
                if (p.getAge() == age) {
                    removeFriends.add(p);
                } 
            }
            friends.removeAll(removeFriends);
        }
    }

编辑: 注意this显然不能解决我的问题。虽然它避免了引发错误,但是JSF显示的结果是不正确的。在我的列表未完全更新时,JSF是否可能正在尝试刷新


EDIT2: 我认为这不是复制品。我在一些测试中遇到的错误随着thisthis一起消失了(请注意,即使使用.add()方法,出于某种原因,我也遇到了相同的错误)。但是JSF仍然没有打印出我所期望的内容。我再次编写BalusC从我的问题中删除的代码,并提供更多信息:

xhtml Java代码:

<c:forEach items="#{personController.groupedPersons}" var="personG">
    <h:commandButton action="#{personController.removeGroup(personG.key)}" type="submit" value="Remove" >
        <f:ajax render="@form" />
    </h:commandButton>
    #{personG.key} - #{personG.value.size()}
</c:forEach>

因此,我第一次执行页面时,personController.groupedPersons返回正确的人员列表(aHashMap<Integer, List<Person>>),并将其打印出来。在这一点上,我有两组:一组是3个年龄相同的人,另一组是另一个年龄不同的人。当我点击3个年龄相同的人组成的小组时,我跟踪代码,并使用迭代器删除所有必要的人,而不引发ConcurrentModificationException。返回的person.getFriends();列表大小为1,这是正确的。然后ajax代码呈现表单personController.groupedPersons再次调用,并按预期返回1个人。我已经核实过了,这就是我真正期待的回归者。但是JSF确实打印了错误的#{personG.key}(我删除的那个)和空的#{personG.value.size()}

我知道这可能很难理解,但你能想出任何解释吗


编辑3: 这更有趣。。。如果我删除了有1个人的组,它就会被删除,然后JSF会正确地打印出有3个人的组。如果我删除包含3个人的组,他们将被删除,JSF将打印(正如我在EDIT2中所说的)我刚刚删除的组的key,size()为空。在修改列表的同时,JSF刷新页面是否可能会出现并发问题?(这最初是我担心的,ConcurrentModificationException来自XHTML和我的托管bean之间的并发问题,而不仅仅是托管bean的代码)。这可以解释为什么我在列表中添加而不是从列表中删除时得到了ConcurrentModificationException


共 (1) 个答案

  1. # 1 楼答案

    在java中,不允许遍历列表(friends)并在循环中从列表中删除元素(friends.remove(p))。这会抛出一个ConcurrentModificationException

    您可以改用Iterator

    Iterator<Person> iterator = friends.iterator();
    while (iterator.hasNext()) {
        if (iterator.next().getAge() == age) {
            iterator.remove();
        }
    }
    

    编辑:

    你的removeFriends.add(p);方法应该有效。您不会得到与此同步的修改异常。但是,如果您的基础列表不支持removeAll,您可能会得到一个UnsupportedOperationException。例如Arrays.asList(...)就是这种情况。如果您将friends列表包装为new ArrayList(friends);,您应该可以开始:

    public void removeGroup(int age) {
      if (person != null) {
        List<Person> friends = new ArrayList<>(person.getFriends());
        List<Person> removeFriends = new ArrayList<>();
        if (friends != null) {
            for (Person p : friends) {
                if (p.getAge() == age) {
                    removeFriends.add(p);
                } 
            }
            friends.removeAll(removeFriends);
        }
    }
    

    之后不要忘记设置好友列表:

    person.setFriends(friends);