我自己的代码

时间:2016-11-04 16:14:59

标签: java jsf-2 concurrentmodification

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

我收到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会返回正确的人员列表(HashMap<Integer, List<Person>>)并打印出来就好了。在这一点上,我有两组:一组3个同龄人和另一个年龄不同的人。当我点击删除 3个年龄相同的人的组时,我会跟踪代码并使用迭代器删除所有必要的人而不提出ConcurrentModificationException。返回的person.getFriends();列表是size = 1,这是正确的。然后ajax代码呈现表单。再次调用personController.groupedPersons并按预期返回1个人。我已经验证了,这是我实际期望的回报者。但是JSF确实打印了错误的#{personG.key}(我删除的那个)和null #{personG.value.size()}

我知道可能很难遵循,但你能想到对此的任何解释吗?

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

1 个答案:

答案 0 :(得分:0)

在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);的方法应该有效。你不会得到一个并发修改异常。但是,如果基础列表不支持UnsupportedOperationException,您最终可能会得到removeAll。这是例如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);