1

Enumeration is Fail-safe. Fail-safe iterators will work on the cloning of the original collection. then why it is throwing concurrentModificationException? please clarify.

Please find my code:

public static void main(String[] args) {

    Vector<String> v=new Vector<String>();
    v.add("Amit");
    v.add("Raj");
    v.add("Pathak");
    v.add("Sumit");
    v.add("Aron");
    v.add("Trek");

    Enumeration en=(Enumeration) Collections.enumeration(v);

    while(en.hasMoreElements())
    {
        String value=(String) en.nextElement();
        System.out.println(value);
        v.remove(value);//modifying the collection

    }

}

Find the error message below

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.Vector$Itr.checkForComodification(Unknown Source)
at java.util.Vector$Itr.next(Unknown Source)
at java.util.Collections$2.nextElement(Unknown Source)
at valar.org.src.EnumerationTest.main(EnumerationTest.java:24)
  • 3
    Vector and Enumeration are obsolete - use `ArrayList` and `Iterator` instead. – assylias Jun 05 '17 at 09:59
  • 1
    yeah, if you are to learn java from books and tutorials, you might want to find some that were written within the last couple of decades. If they are teaching that stuff to you in some school, in 2017, you might want to change school. – Mike Nakis Jun 05 '17 at 10:06
  • @assylias Even ArrayList with Enumeration throws ConcurrentModificationException. My doubt here is that why enumeration throws this exception when Enumeration is Fail-safe. – user6426361 Jun 05 '17 at 10:06
  • Your issue is the interpretation of what `Collections.enumeration(v)` does. Why do you expect that to clone something? – Tom Jun 05 '17 at 10:09
  • You'll get different results from `v.elements()` than `Collections.enumeration(v)`, by the way. `Collections.enumeration(v)` gets an iterator and uses that to produce the enumeration. Check the `Collections` source code. – David Conrad Jun 05 '17 at 10:23
  • @user6426361 Enumeration is obsolete, don't use it. Use an Iterator instead and its `remove` method. – assylias Jun 05 '17 at 10:33
  • See for example: https://stackoverflow.com/a/223929/829571 – assylias Jun 05 '17 at 10:33

4 Answers4

2

Collections.enumeration(Collection) will create an iterator from the collection passed as parameter :

public static <T> Enumeration<T> enumeration(final Collection<T> c) {
    return new Enumeration<T>() {
        private final Iterator<T> i = c.iterator();

        public boolean hasMoreElements() {
            return i.hasNext();
        }

        public T nextElement() {
            return i.next();
        }
    };
}

It means that the iterator is backed to the collection which you remove element in the iterator loop and you cannot remove an element of the collection on which you iterate with the iterator.

You should create a copy of the Vector you pass in the enumeration() invocation :

Enumeration<String> en = Collections.enumeration(new Vector<String>(v));

And as a side note, you should favor List interface and ArrayList implementation over Vector (that is synchronized) and declare generics collection that spares cast and increase the type safety of the code.

So it would give this code (I left the Vector use as it is maybe a not modifiable constraint but I specified the generics as it is often simpler to add even in a legacy code):

Vector<String> v = new Vector<String>();
v.add("Amit");
v.add("Raj");
v.add("Pathak");
v.add("Sumit");
v.add("Aron");
v.add("Trek");

Enumeration<String> en = Collections.enumeration(new Vector<String>(v));

while (en.hasMoreElements()) {
    String value = (String) en.nextElement();
    System.out.println(value);
    v.remove(value);// modifying the collection
}
davidxxx
  • 125,838
  • 23
  • 214
  • 215
1

Your Enumeration uses an Iterator internally. While iterating over the elements, you can't use the vector itself to remove items. You have to use the iterator. But you don't have access to it. Create an iterator instead:

public static void main(String[] args) {

    final Vector<String> v = new Vector<String>();
    v.add("Amit");
    v.add("Raj");

    // Use an Iterator to remove the value you are iterating over
    final Iterator<String> iterator = v.iterator();

    while (iterator.hasNext()) {
        final String value = iterator.next();
        System.out.println(value);
        iterator.remove();
    }
}

Though Vector is practically deprecated anyways. You should propably use a List instead:

The imports for the correct Lists (don't use the awt.List for this):

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

The changed code:

public static void main(String[] args) {

    final List<String> v = new ArrayList<>();
    v.add("Amit");
    v.add("Raj");
    v.add("Pathak");

    final Iterator<String> iterator = v.iterator();

    while (iterator.hasNext()) {
        final String value = iterator.next();
        System.out.println(value);
        iterator.remove();
    }
}

Also note you can use the interface as Type which is generally preferred to using the implementation.

Edit:

Looking at your example, maybe what you really need is a queue:

public static void main(String[] args) {

    final Queue<String> v = new LinkedList<>();
    v.add("Amit");
    v.add("Raj");
    v.add("Pathak");

    System.out.println("Size: " + v.size());
    for (String element = v.poll(); element != null; element = v.poll()) {
        System.out.println(element);
    }
    System.out.println("Size: " + v.size());
}

Output:

Size: 3
Amit
Raj
Pathak
Size: 0

This works the same as your example. For more info on Collections see The official Collections Java Trail

Dennux
  • 240
  • 1
  • 8
  • I also think you should use a way younger tutorial to learn java. Vector is generally not used anymore. Especially not in tutorials. I don't have any English tutorials at hand that i know of is good. But you should find some very quick – Dennux Jun 05 '17 at 10:18
  • (But it already uses an `Iterator`, because `Collections.enumeration` uses an `Iterator`.) – David Conrad Jun 05 '17 at 10:29
  • @David Conrad: That is the point. That is exactly my point. Please read my answer carefully and think about what is happening when Enumeration uses an Iterator internally. Look at the first sentence in my answer ... – Dennux Jun 05 '17 at 10:31
0

Enumeration is Fail-safe.

Correct. (Allowing for some language difficulties.)

Fail-safe iterators will work on the cloning of the original collection.

Correct. (Allowing for some language difficulties.)

then why it is throwing concurrentModificationException?

Because there is no cloning involved.

Where is the cloning?

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
0

You are using Enumeration which is not supported removed method.Once you created a Enumeration then it test for checkForComodification .so when you do the remove from vector the modCount increases and expectedModCount not modified.

 final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }

please modify your code using iterator

public static void main(String[] args) {

        Vector<String> v = new Vector<String>();
        v.add("Amit");
        v.add("Raj");
        v.add("Pathak");
        v.add("Sumit");
        v.add("Aron");
        v.add("Trek");

        Iterator<String> it =v.iterator();

        while (it.hasNext()) {
            String value = it.next();
            System.out.println(value);
            it.remove();

        }

    }
gati sahu
  • 2,576
  • 2
  • 10
  • 16