Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Enumeration vs Iterator

Tags:

java

Enumeration doesn't throw ConcurrentModificationException , why?

See below 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<String> en=v.elements();

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

    }

}

It only prints :

Amit
Pathak
Aron

Why is this such behavior . Can we say that Enumerator is thread safe.

Edit: When working with Iterator it throws ConcurrentModificationException in single thread application.

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=(String) it.next();
        System.out.println(value);
        v.remove(value);
    }
}

Please check.

like image 201
amicngh Avatar asked Jun 04 '12 10:06

amicngh


2 Answers

Note that ConcurrentModificationException has nothing to do with concurrency in the sense of multithreading or thread safety. Some collections allow concurrent modifications, some don't. Normally you can find the answer in the docs. But concurrent doesn't mean concurrently by different threads. It means you can modify the collection while you iterate.

ConcurrentHashMap is a special case, as it is explicitly defined to be thread-safe AND editable while iterated (which I think is true for all thread-safe collections).

Anyway, as long as you're using a single thread to iterate and modify the collection, ConcurrentHashMap is the wrong solution to your problem. You are using the API wrongly. You should use Iterator.remove() to remove items. Alternatively, you can make a copy of the collection before you iterate and modify the original.

EDIT:

I don't know of any Enumeration that throws a ConcurrentModificationException. However, the behavior in case of a concurrent modification might not be what you expect it to be. As you see in you example, the enumeration skips every second element in the list. This is due to it's internal index being incremented regardless of removes. So this is what happens:

  • en.nextElement() - returns first element from Vector, increments index to 1
  • v.remove(value) - removes first element from Vector, shifts all elements left
  • en.nextElement() - returns second element from Vector, which now is "Pathak"

The fail-fast behavior of Iterator protects you from this kind of things, which is why it is generally preferable to Enumberation. Instead, you should do the following:

Iterator<String> it=v.iterator();
while(it.hasNext())
{
    String value=(String) it.next();
    System.out.println(value);
    it.remove(); // not v.remove(value); !!
}

Alternatively:

for(String value : new Vector<String>(v)) // make a copy
{
    String value=(String) it.next();
    System.out.println(value);
    v.remove(value);
}

The first one is certainly preferable, as you don't really need the copy as long as you use the API as it is intended.

like image 139
sfussenegger Avatar answered Oct 11 '22 13:10

sfussenegger


Enumeration doesn't throw ConcurrentModificationException , why?

Because there is no path in the code being invoked which throws this exception. Edit: I am referring to the implementation provided by the Vector class, not about the Enumeration interface in general.

Why is this such behavior . Can we say that Enumerator is thread safe.

It is thread-safe in a sense that the code executed is properly synchronized. However, I don't think the result your loop yields is what you would except.

The reason for your output is that the Enumeration object maintains a counter, which is incremented after every invokation of nextElement(). This counter is not aware of your invokation of remove().

like image 38
MartinK Avatar answered Oct 11 '22 13:10

MartinK