I keep getting java.util.concurrentmodificationexception.. How to fix this?

久未见 提交于 2019-12-24 06:06:16

问题


I've been working on this snippet of code. Here is the pseudocode of what I want to happen:

a.check if sections(which is a list) size is 0.
b.if sections size is 0, then automatically enroll the student to the section by calling sections.add(newSection)
c.else if sections size is not zero, check for conflicts with schedule
d.if there are no conflicts, then enroll the student to the section by calling sections.add(newSection)
e.else do nothing

Java keeps throwing "java.util.concurrentmodificationexception" error on me. I know, I'm not supposed to alter the size of the ArrayList while traversing the list because it will modify the iterator. Is there another way to solve this? :D

Thanks a lot. Your help is highly appreciated. :)

 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();
    }

回答1:


Don't do sections.add(newSection) inside your for loop, as this is a modification of the collection you're currently iterating over.

Also, don't you want to check all sections before deciding whether to add the newSection or not? Maybe something like this:

boolean conflict = false;
for (...) {
  if (/* check for conflict */) {
    conflict = true;
    break;
  }
}
if (!conflict) {
  sections.add(newSection);
}



回答2:


From the javadoc for ConcurrentModificationException (my emphasis):

This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.

For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances. Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.

Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.

Potential solution: instead of adding directly to the list you're iterating, add to a temporary list and then when you've finished iterating, do an addAll().




回答3:


While iterating collection, you can't modify it. The line this.sections.add(newSection); throwing the exception. You may need to use some boolean marker to check the condition

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

After the for loop if your boolean marker is true, then you can write

 this.sections.add(newSection);  
                    result.append(resultPositive);



回答4:


You're correct in your assumption,

 this.sections.add(newSection);  

is definitely the source of your problem.

Simplest solution: Have a boolean representing the section's availability. Start out assuming it is available. If there is any conflict in your iterator, set it to false. After the iterator, add the section if the section is available (boolean true).




回答5:


ConcurrentModificationExceptions often occur when you are modifying a collection while you are iterating over its elements. Read this tutorial for more details and this old SO post Why does it.next() throw java.util.ConcurrentModificationException?




回答6:


I agree with @sudocode that you don't want to be adding the newSection every time you find even a section which doesn't conflict. I would have thought that when you step through the code in your debugger this would be apparent. ;)

BTW another (more obscure) way to do this without a flag is

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

  sections.add(newSection);
}


来源:https://stackoverflow.com/questions/8715322/i-keep-getting-java-util-concurrentmodificationexception-how-to-fix-this

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!