当我尝试使用相同的代码对对象的值求和时,java.util.ConcurrentModificationException

时间:2013-09-23 05:03:20

标签: java list arraylist

请说我的英语不是很好,也不是编程的初学者,所以请耐心等待。

请先查看我的代码,以便更好地了解我遇到的问题。

我创建了一个名为 ObjAbc.java 的对象:

package exer;

public class ObjAbc {
    private Integer code;
    private Integer value;

    public ObjAbc () {

    }

    public ObjAbc (Integer code, Integer value) {
            this.code = code;
            this.value = value;
    }

    public Integer getCode() {
            return code;
    }

    public void setCode(Integer code) {
            this.code = code;
    }

    public Integer getValue() {
            return value;
    }

    public void setValue(Integer value) {
            this.value = value;
    }

    @Override
    public String toString() {
           return "ObjAbc [code=" + code + ", value=" + value + "]";
    }
}

然后我有一个班级 ObjAbcTest.java

package exer;

import java.util.ArrayList;
import java.util.List;

public class ObjAbcTest {

    public static List<ObjAbc> populateList() {
        List<ObjAbc> objAbcs = new ArrayList<ObjAbc>();
        objAbcs.add(new ObjAbc(1, 11));
        objAbcs.add(new ObjAbc(2, 25));
        objAbcs.add(new ObjAbc(3, 125));
        objAbcs.add(new ObjAbc(4, 73));
        objAbcs.add(new ObjAbc(5, 12));
        objAbcs.add(new ObjAbc(1, 12));
        objAbcs.add(new ObjAbc(3, 1));
        return objAbcs;
    }

    public static void main(String[] args) {
        List<ObjAbc> list = populateList();
        List<ObjAbc> newList = new ArrayList<ObjAbc>();
        for (ObjAbc o : list) {
            if (!newList.isEmpty()) {
                for (ObjAbc n : newList) {
                    if (o.getCode().intValue() == n.getCode().intValue()) {
                        n.setValue(n.getValue() + o.getValue());
                        break;
                    } 
                    else {
                        newList.add(o);
                    }
                }
            } 
            else {
                newList.add(o);
            }
        }

        for (ObjAbc n : newList) 
            System.out.println(n.toString());
    }
}

我想要做的是将所有具有相同代码的ObjAbc的所有值相加,但在我总结值后删除另一个ObjAbc,这意味着该对象必须显示一次但是值应该是总数。

示例:

输入:

ObjAbc [code=1, value=11]
ObjAbc [code=2, value=25]
ObjAbc [code=3, value=125]
ObjAbc [code=4, value=73]
ObjAbc [code=5, value=12]
ObjAbc [code=1, value=12]
ObjAbc [code=3, value=1]

预期产出:

ObjAbc [code=1, value=23]
ObjAbc [code=2, value=25]
ObjAbc [code=3, value=126]
ObjAbc [code=4, value=73]
ObjAbc [code=5, value=12]

但我得到的是:

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
    at java.util.AbstractList$Itr.next(AbstractList.java:343)
    at exer.ObjAbcTest.main(ObjAbcTest.java:25)

5 个答案:

答案 0 :(得分:2)

这应该有效(未经测试)。

public class ObjAbcTest {

    public static List<ObjAbc> populateList() {
            // same as yours
    }

    public static void main(final String[] args) {
        final List<ObjAbc> list = populateList();
        final Map<Integer, Integer> sums = new HashMap<Integer, Integer>();

        // compute sums
        for (final ObjAbc obj: list) {
            // this if can be simplified with ? operator
            if (sums.containsKey(obj.getCode())) {
                sums.put(obj.getCode(), sums.get(obj.getCode()) + obj.getValue());
            } else {
                sums.put(obj.getCode(), obj.getValue());
            }
        }

        // populates newList
        final List<ObjAbc> newList = new ArrayList<ObjAbc>();
        for (final Map.Entry<Integer, Integer> e : sums.entrySet()) {
            newList.add(new ObjAbc(e.getKey(), e.getValue()));
        }

        // TODO: sort?

        // outputs
        for (final ObjAbc n : newList) 
            System.out.println(n.toString());
        }
}

我们在这里使用Map(代码=&gt;总和)来存储总和。

答案 1 :(得分:1)

您正在通过

修改newList
 newList.add() 
迭代列表时

 for (ObjAbc n : newList)

使迭代器无效。

例如,您可以使用ListIterator,它允许您在迭代时修改列表。例如:

 ListIterator<ObjAbc> li = newList.listIterator();
 while (li.hasNext()) {
    ObjAbc n = li.next();
    if (...) 
    else {
      li.add(...)
    }
 }

答案 2 :(得分:0)

对于Java中的每个循环使用隐式迭代器。并且ArrayList的迭代器是故障快速设计。一旦检测到基础结构(列表)的变化,它就会抛出ConcurrentModificationException

基本上,列表现在已经“修改”,迭代器对应于列表的先前状态。运行时检测到这一点并抛出异常。

阅读here了解如何处理此类案件。

答案 3 :(得分:0)

newList.add(o);

在迭代集合时,您无法修改它。

这是添加时的问题。

您可以做的只是采取另一个列表并添加项目。

答案 4 :(得分:0)

我修复了你的代码,问题是在第二个循环中添加,是不正确的,因为你尝试添加新值,如果它与newList中的第一个元素不匹配。

这应该有效:     包裹exer;

import java.util.ArrayList;
import java.util.List;

public class ObjAbcTest {

    public static List<ObjAbc> populateList() {
        List<ObjAbc> objAbcs = new ArrayList<ObjAbc>();
        objAbcs.add(new ObjAbc(1, 11));
        objAbcs.add(new ObjAbc(2, 25));
        objAbcs.add(new ObjAbc(3, 125));
        objAbcs.add(new ObjAbc(4, 73));
        objAbcs.add(new ObjAbc(5, 12));
        objAbcs.add(new ObjAbc(1, 12));
        objAbcs.add(new ObjAbc(3, 1));
        return objAbcs;
    }

    public static void main(String[] args) {
        List<ObjAbc> list = populateList();
        List<ObjAbc> newList = new ArrayList<ObjAbc>();
        for (ObjAbc o : list) {
            if (!newList.isEmpty()) {
                boolean found = false;
                for (ObjAbc n : newList) {
                    if (o.getCode().intValue() == n.getCode().intValue()) {
                        n.setValue(n.getValue() + o.getValue());
                        found = true;
                    } 
                }
                if (!found) {
                    newList.add(o);
                }
            } 
            else {
                newList.add(o);
            }
        }

        for (ObjAbc n : newList) 
            System.out.println(n.toString());
    }
}