使用嵌套迭代器删除没有ConcurrentModificationException的集合项

时间:2014-12-19 17:00:29

标签: java android concurrentmodification

我正在忍受这个异常,在阅读完之后我明白你通常可以使用Iterator处理它。但尝试过,我发现它在这种情况下不起作用,也许是因为我有两个嵌套循环?所有代码都在主线程(Android)上运行。

 private boolean removeRoutesWithTimestampFromTeams(long time) {
    boolean routesRemoved = false;
    Iterator<WhizzyTeam> teamIterator = assignedTeams.iterator();
    while (teamIterator.hasNext()) {
        WhizzyTeam team = teamIterator.next();  // EXCEPTION HERE
        Iterator<Route> routeIterator = team.routes.iterator();
        while (teamIterator.hasNext()) {
            Route route = routeIterator.next();
            if (route.whizzy_assignment_time_in_millis == time) {
                team.removeRoute(route);
                routesRemoved = true;
            }
        }
        if (team.routes == null || team.routes.size() == 0) {
            assignedTeams.remove(team);
            unassignedTeams.add(team);
        }
    }
    return routesRemoved;

我依靠对象引用来识别对象,因此复制集合是一个非常不吸引人的选择。有没有办法在不诉诸副本的情况下做我需要做的事情?

=====工作代码=====

我实际上犯了三个在这里修复的错误。 我在两个循环中使用了相同的迭代器(在上面的代码中也修复了) 2.我应该使用Iterator.remove() 3.在removeRoute()中,还有另一个(不必要的)for循环遍历路由以删除类似的兄弟

private boolean removeRoutesWithTimestampFromTeams(long time) {
    boolean routesRemoved = false;
    Iterator<WhizzyTeam> teamIterator = assignedTeams.iterator();
    while (teamIterator.hasNext()) {
        WhizzyTeam team = teamIterator.next();
        Iterator<Route> routeIterator = team.routes.iterator();
        while (routeIterator.hasNext()) {
            Route route = routeIterator.next();
            if (route.whizzy_assignment_time_in_millis == time) {
                routeIterator.remove();
                routesRemoved = true;
            }
        }
        if (team.routes == null || team.routes.size() == 0) {
            teamIterator.remove();
            unassignedTeams.add(team);
        }
    }
    return routesRemoved;
}

2 个答案:

答案 0 :(得分:1)

我发布了您发布的代码段的两个问题。第一个使用外部迭代器的内部循环

  while (teamIterator.hasNext()) {
        WhizzyTeam team = teamIterator.next();  // EXCEPTION HERE
        Iterator<Route> routeIterator = team.routes.iterator();
        while (teamIterator.hasNext()) {

我确实认为你应该使用routeIterator代替第二个循环中的teamIterator

其次,您没有使用Iterator界面中的remove方法从集合中删除项目。来自doc

  

此类的迭代器和listIterator返回的迭代器   方法是快速失败的:如果列表在结构上被修改了   创建迭代器之后的时间,除了通过之外的任何方式   迭代器自己删除或添加方法,迭代器会抛出一个   ConcurrentModificationException的。因此,面对并发   修改,迭代器快速而干净地失败,而不是   在不确定的时间冒着任意的,非确定性的行为   在将来。

答案 1 :(得分:1)

正如您所知,使用嵌套迭代器可能会导致混淆使用错误的等等。在没有迭代器的情况下执行此操作的另一种方法是在迭代时跟踪要删除的内容,然后删除它们。这种方法确实需要临时集合,但允许您使用foreach循环并使用错误的迭代器来防止错误。

private boolean removeRoutesWithTimestampFromTeams(long time) {
    boolean routesRemoved = false;
    List<WhizzyTeam> teamsToUnassign = new ArrayList<>();
    for( WhizzyTeam team : assignedTeams ) {
        List<Route> routesToRemove = new ArrayList<>();
        for( Route route : team.routes ) {
            if (route.whizzy_assignment_time_in_millis == time) {
                routesToRemove.add( route );
            }
        }
        if( routesToRemove.size() > 0 ) {
            team.routes.removeAll( routesToRemove );
            if( team.routes.isEmpty() ) {
                teamsToUnassign.add( team );
            }
            routesRemoved = true;
        }
    }
    assignedTeams.removeAll( teamsToUnassign );
    unassignedTeams.addAll( teamsToUnassign );

    return routesRemoved;
}
相关问题