0

I have my code as below and I'm getting ConcurrentModificationException, particularly in the line for (String file : files)

I don't change anything for the "file" when doing iteration, so why the exception will be caused and how should I avoid it? Thanks for any suggestion!

int getTotalLength(final HashSet<String> files) {
        int total = 0;
        int len;
        for (String file : files) {
            len = getLength(file);
            if (len != Long.MIN_VALUE) {
                total += len;
            }
        }
        return total;
    }




      int getLength(String file) {
        int len = Long.MIN_VALUE;

        if (file == null) {
            return len;
        }

        File f = new File(file);

        if (f.exists() && f.isFile()) {
            len = f.length();
        }

        return size;
    }
Green Ho
  • 881
  • 3
  • 14
  • 27
  • 1
    Well do you have any other threads that might be modifying the set at the same time? – Jon Skeet Aug 20 '13 at 20:20
  • yes, it's possible but I have made the hashSet final... wouldn't it prevent the set getting modified? – Green Ho Aug 20 '13 at 20:25
  • ConcurrentModification is on your HashSet, not on your file – Plínio Pantaleão Aug 20 '13 at 20:25
  • 1
    @GreenHo: No, you've made the *variable* `final`. That has nothing to do with whether or not the *object* that the variable's value refers to can be modified. – Jon Skeet Aug 20 '13 at 20:26
  • @JonSkeet This kind of confusion is a large part of why I yearn for `const` in Java, not to mention that it would obviate the need for Guava's `Immutable*` classes. :-D – C. K. Young Aug 20 '13 at 20:32
  • @JonSkeet: Sorry, I'm still confused. I do have multithreads running that would potentially add new elements to the HashSet ("files"), but inside the getTotalLength() method, the HashSet is final and it shouldn't be modified in this method, am I missing anything here? – Green Ho Aug 20 '13 at 20:35
  • by "the object that the variable's value refers to", do you mean the file itself? I think the exception happens to the HashSet? – Green Ho Aug 20 '13 at 20:36
  • @GreenHo: No, I mean the `HashSet`. You've fundamentally understood the meaning of `final`. – Jon Skeet Aug 20 '13 at 20:37

1 Answers1

3

Refering to you comment, declaring final HashSet<String> files makes variable files finale - that means that you cannot assign another object to this variable inside this variable's scope. HashSet itself is mutable object and can be modified - it has nothing to do with final modifier (reference to the set object itselt is still the same). If you want to work concurently on same object (same hashset) use synchronized blocks or methods.

Generally speaking, you cannot modify collection (in same or another thread) that are beeing iterated with for loop in for-each alike variant.

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • The caller (say, callerA ) that calls getTotalLength() is a already synchronized method and the callerA doesn't modify the collection, but callerB that calls callerA modifies the collection... the code looks like this void callerB() { modify the HashSet; callerA(); } void callerA() { calls getTotalLength() where i get the exception } – Green Ho Aug 20 '13 at 22:16
  • Should I use synchronized block in caller B such that void callerB() { synchronized (the HashSet) { modify the hashSet; callerA() which iterates the hashSet; } } – Green Ho Aug 20 '13 at 22:37
  • If the method (as you refered to "synchronized method") is synchronized, that means that if one thread is executing such method (is "inside" of it), no another thread is allowed to execute that method, until previous execution is over. If you have synchronized two different methods (with `synchronized` keyword in method signature), they are not synchronized to each other. You have to explicitly synchronize your code on common object to both methods you want to synchronize. – Antoniossss Aug 21 '13 at 05:18