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")