This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-collections.git


The following commit(s) were added to refs/heads/master by this push:
     new 651a62189 Update index on remove via IndexedCollection iterator (#724)
651a62189 is described below

commit 651a6218910a906dc50415c145d63ba06c07a659
Author: Naveed Khan <[email protected]>
AuthorDate: Wed Aug 12 15:06:23 2026 +0000

    Update index on remove via IndexedCollection iterator (#724)
    
    iterator() was not overridden, so removing through the decorator's own 
iterator left the index MultiMap holding the removed element.
---
 .../collections4/collection/IndexedCollection.java | 31 ++++++++++++++++++++++
 .../collection/IndexedCollectionTest.java          | 23 ++++++++++++++++
 2 files changed, 54 insertions(+)

diff --git 
a/src/main/java/org/apache/commons/collections4/collection/IndexedCollection.java
 
b/src/main/java/org/apache/commons/collections4/collection/IndexedCollection.java
index c18ca3922..4213c7f07 100644
--- 
a/src/main/java/org/apache/commons/collections4/collection/IndexedCollection.java
+++ 
b/src/main/java/org/apache/commons/collections4/collection/IndexedCollection.java
@@ -24,6 +24,7 @@ import java.util.function.Predicate;
 
 import org.apache.commons.collections4.MultiMap;
 import org.apache.commons.collections4.Transformer;
+import org.apache.commons.collections4.iterators.AbstractIteratorDecorator;
 import org.apache.commons.collections4.map.MultiValueMap;
 
 /**
@@ -188,6 +189,11 @@ public class IndexedCollection<K, C> extends 
AbstractCollectionDecorator<C> {
         return coll == null ? null : coll.iterator().next();
     }
 
+    @Override
+    public Iterator<C> iterator() {
+        return new IndexedCollectionIterator(decorated().iterator());
+    }
+
     /**
      * Clears the index and re-indexes the entire decorated {@link Collection}.
      */
@@ -274,4 +280,29 @@ public class IndexedCollection<K, C> extends 
AbstractCollectionDecorator<C> {
         return (Collection<C>) index.get(key);
     }
 
+    /**
+     * Iterator that keeps the index in sync when {@code remove()} is used.
+     */
+    private final class IndexedCollectionIterator extends 
AbstractIteratorDecorator<C> {
+
+        private C lastReturned;
+
+        private IndexedCollectionIterator(final Iterator<C> iterator) {
+            super(iterator);
+        }
+
+        @Override
+        public C next() {
+            lastReturned = super.next();
+            return lastReturned;
+        }
+
+        @Override
+        public void remove() {
+            super.remove();
+            removeFromIndex(lastReturned);
+            lastReturned = null;
+        }
+    }
+
 }
diff --git 
a/src/test/java/org/apache/commons/collections4/collection/IndexedCollectionTest.java
 
b/src/test/java/org/apache/commons/collections4/collection/IndexedCollectionTest.java
index c79810f17..94f3b703c 100644
--- 
a/src/test/java/org/apache/commons/collections4/collection/IndexedCollectionTest.java
+++ 
b/src/test/java/org/apache/commons/collections4/collection/IndexedCollectionTest.java
@@ -18,6 +18,7 @@ package org.apache.commons.collections4.collection;
 
 import static java.util.Arrays.asList;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -26,6 +27,7 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Iterator;
 
 import org.apache.commons.collections4.Transformer;
 import org.junit.jupiter.api.Test;
@@ -166,6 +168,27 @@ class IndexedCollectionTest extends 
AbstractCollectionTest<String> {
         assertEquals("3", indexed.get(3));
     }
 
+    @Test
+    void testIteratorRemoveUpdatesIndex() {
+        final IndexedCollection<Integer, String> indexed = 
decorateUniqueCollection(new ArrayList<>());
+        indexed.add("1");
+        indexed.add("2");
+
+        final Iterator<String> it = indexed.iterator();
+        while (it.hasNext()) {
+            if ("1".equals(it.next())) {
+                it.remove();
+            }
+        }
+
+        assertFalse(indexed.contains("1"));
+        assertNull(indexed.get(1));
+        assertEquals(1, indexed.size());
+        // the unique index must no longer report the removed key
+        indexed.add("1");
+        assertEquals("1", indexed.get(1));
+    }
+
     @Test
     void testRemovePreservesRemainingValuesWithSameTransformedKey() {
         @SuppressWarnings("unchecked")

Reply via email to