2

我一直在研究这段代码。这是我想要发生的伪代码:

a.检查sections(这是一个列表)大小是否为
0。b.如果sections大小为0,则通过调用sections.add(newSection)自动将学生注册到该部分
c.else如果sections大小不为零,请检查d.如果没有冲突
,则通过调用sections.add(newSection)
e.else将学生注册到该部分

Java 不断向我抛出“java.util.concurrentmodificationexception”错误。我知道,我不应该在遍历列表时更改 ArrayList 的大小,因为它会修改迭代器。还有其他方法可以解决这个问题吗?:D

非常感谢。非常感谢您的帮助。:)

 public String enrollsTo(Section newSection){


        StringBuffer result = new StringBuffer();

        String resultNegative = "Failed to enroll in this section.";
        String resultPositive = "Successfully enrolled in section: " + newSection.getSectionName() + ".";

        int previousSectionSize = sections.size();

        if(this.sections.isEmpty()){
            this.sections.add(newSection);
            result.append(resultPositive);
        }else{
            for(Iterator<Section> iterator = sections.iterator(); iterator.hasNext() ; ){
                Section thisSection = iterator.next();

                if(thisSection.conflictsDayWith(newSection)==false &&
                    thisSection.conflictsTimeWith(newSection)==false){
                    this.sections.add(newSection);  //<-- i believe the problem lies here.
                    result.append(resultPositive);
                }
            }
        }
//      if(this.sections.size() == previousSectionSize){
//          result.append(resultNegative);
//      }
        return result.toString();
    }
4

6 回答 6

1

不要sections.add(newSection)在你的 for 循环中做,因为这是对你当前迭代的集合的修改。

另外,您不想在决定是否添加之前检查所有部分newSection吗?也许是这样的:

boolean conflict = false;
for (...) {
  if (/* check for conflict */) {
    conflict = true;
    break;
  }
}
if (!conflict) {
  sections.add(newSection);
}
于 2012-01-03T16:35:20.030 回答
0

你的假设是正确的,

 this.sections.add(newSection);  

绝对是你问题的根源。

最简单的解决方案:有一个表示该部分可用性的布尔值。开始假设它可用。如果您的迭代器中存在任何冲突,请将其设置为 false。在迭代器之后,如果该部分可用,则添加该部分(布尔值 true)。

于 2012-01-03T16:35:22.333 回答
0

当您在迭代集合的元素时修改集合时,经常会发生 ConcurrentModificationExceptions。阅读本教程以获取更多详细信息和这篇旧的 SO 帖子Why does it.next() throw java.util.ConcurrentModificationException?

于 2012-01-03T16:35:35.213 回答
0

来自ConcurrentModificationException的javadoc (我的重点):

当这种修改是不允许的时,检测到对象的并发修改的方法可能会抛出此异常。

例如,通常不允许一个线程在另一个线程对其进行迭代时修改 Collection。一般来说,在这些情况下,迭代的结果是不确定的。如果检测到此行为,某些迭代器实现(包括 JRE 提供的所有通用集合实现的那些)可能会选择抛出此异常。这样做的迭代器被称为快速失败迭代器,因为它们快速而干净地失败,而不是在未来不确定的时间冒着任意的、非确定性的行为的风险。

请注意,此异常并不总是表示对象已被不同的线程同时修改。如果单个线程发出一系列违反对象约定的方法调用,则该对象可能会抛出此异常。例如,如果线程在使用快速失败迭代器迭代集合时直接修改了集合,则迭代器将抛出此异常。

请注意,不能保证快速失败的行为,因为一般来说,在存在不同步的并发修改的情况下,不可能做出任何硬保证。快速失败操作会尽最大努力抛出 ConcurrentModificationException。因此,编写一个依赖此异常来确保其正确性的程序是错误的:ConcurrentModificationException 应该仅用于检测错误。

潜在的解决方案:不要直接添加到您正在迭代的列表中,而是添加到一个临时列表中,然后当您完成迭代时,执行addAll().

于 2012-01-03T16:33:36.973 回答
0

在迭代集合时,您不能修改它。this.sections.add(newSection); 抛出异常的行。您可能需要使用一些布尔标记来检查条件

if(thisSection.conflictsDayWith(newSection)==false &&
                    thisSection.conflictsTimeWith(newSection)==false)

在 for 循环之后,如果您的布尔标记为真,那么您可以编写

 this.sections.add(newSection);  
                    result.append(resultPositive);
于 2012-01-03T16:34:19.823 回答
0

我同意@sudocode 的观点,即您不想在每次找到不冲突的部分时都添加 newSection。我原以为当您在调试器中单步执行代码时,这会很明显。;)

顺便说一句,另一种(更晦涩)没有标志的方法是

CHECK: {
  for (...) {
    if (/* check for conflict */) 
      break CHECK;
  }

  sections.add(newSection);
}
于 2012-01-03T16:55:47.037 回答