简体   繁体   中英

Java: `iterator.remove` throws IllegalStateException

I have an iterator inside a thread and I am trying to remove the duplicate records.

 Runnable readingThread = new Runnable() {
        @Override
        public void run() {

            Iterator<Demand> iterator = null;
            for (iterator = demandListFromFile.iterator(); iterator.hasNext();) {
                Demand demand = iterator.next();

                /**
                 * Find and assign the Item ID
                 */
                if (itemListHashMap.containsValue(demand.getItem().getItemName())) {
                    demand.getItem().setIditem(itemListHashMapReversed.get(demand.getItem().getItemName()));

                } else {
                    unavailableItemsList.add(demand.getItem().getItemName());
                }


                /**
                 * Find and remove duplicate records
                 */
                for (Map.Entry<Date, String> entry : demandListHashMap.entries()) {

                    if (demand.getDueDate().equals(entry.getKey()) && demand.getItem().getItemName().equals(entry.getValue())) {

                        iterator.remove();
                    }

                }

            }

        }

After removing few items, the iterator.remove throws the below exception

Exception in thread "Thread-0" java.lang.IllegalStateException
    at java.base/java.util.ArrayList$Itr.remove(ArrayList.java:1009)
    at com.xxx.xxx.ui.Home$7.run(Home.java:455)
    at java.base/java.lang.Thread.run(Thread.java:834)

Why is this happening? Please note I have removed the code after and before the iterator, to keep this post short.

Iterator.java remove method:

    @throws IllegalStateException if the next method has not
              yet been called, or the remove method has already
              been called after the last call to the next method
    void remove() {
        ..
    }

The problem is in your for loop "Find and remove duplicate records" you may be calling iterator.remove more than once. The remove method removes the current element you are viewing so you can only call it once per using next(). To ensure it's called only once, add a break statement below iterator.remove();

The reason stated by @CausingUnderflowsEverywhere was absolutely right.

Adding to that, after seeing the implementation, iterator.remove element calls the ArrayList.remove method internally.

ArrayList is maintaining the index of the last element returned in a variable called lastRet Once the element is removed, the ArrayList.remove method set the lastRet to -1.

And the very first check of ArrayList.remove is

if (lastRet < 0)
{
     throw new IllegalStateException();
}

This is what happens in the background.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM