[COLLECTIONS-802] Fix remove failed by removing set null to currentKey and currentValue.

This commit is contained in:
samabcde 2022-04-25 00:07:27 +08:00
parent 9df6f64b7e
commit 43e23dd658
2 changed files with 30 additions and 13 deletions

View File

@ -772,8 +772,8 @@ public abstract class AbstractReferenceMap<K, V> extends AbstractHashedMap<K, V>
// These fields keep track of where we are in the table.
int index;
ReferenceEntry<K, V> entry;
ReferenceEntry<K, V> previous;
ReferenceEntry<K, V> next;
ReferenceEntry<K, V> current;
// These Object fields provide hard references to the
// current and next entry; this assures that if hasNext()
@ -794,23 +794,21 @@ public abstract class AbstractReferenceMap<K, V> extends AbstractHashedMap<K, V>
public boolean hasNext() {
checkMod();
while (nextNull()) {
ReferenceEntry<K, V> e = entry;
ReferenceEntry<K, V> e = next;
int i = index;
while (e == null && i > 0) {
i--;
e = (ReferenceEntry<K, V>) parent.data[i];
}
entry = e;
next = e;
index = i;
if (e == null) {
currentKey = null;
currentValue = null;
return false;
}
nextKey = e.getKey();
nextValue = e.getValue();
if (nextNull()) {
entry = entry.next();
next = next.next();
}
}
return true;
@ -831,27 +829,27 @@ public abstract class AbstractReferenceMap<K, V> extends AbstractHashedMap<K, V>
if (nextNull() && !hasNext()) {
throw new NoSuchElementException();
}
previous = entry;
entry = entry.next();
current = next;
next = next.next();
currentKey = nextKey;
currentValue = nextValue;
nextKey = null;
nextValue = null;
return previous;
return current;
}
protected ReferenceEntry<K, V> currentEntry() {
checkMod();
return previous;
return current;
}
public void remove() {
checkMod();
if (previous == null) {
if (current == null) {
throw new IllegalStateException();
}
parent.remove(currentKey);
previous = null;
current = null;
currentKey = null;
currentValue = null;
expectedModCount = parent.modCount;

View File

@ -26,6 +26,7 @@ import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@ -315,6 +316,24 @@ public class ReferenceMapTest<K, V> extends AbstractIterableMapTest<K, V> {
}
/**
* Test whether remove is not removing last entry after calling hasNext.
* <p>
* See <a href="https://issues.apache.org/jira/browse/COLLECTIONS-802">COLLECTIONS-802: ReferenceMap iterator remove violates contract</a>
*/
@Test
public void testIteratorLastEntryCanBeRemovedAfterHasNext() {
ReferenceMap<Integer, Integer> map = new ReferenceMap<>();
map.put(1, 2);
Iterator<Map.Entry<Integer, Integer>> iter = map.entrySet().iterator();
assertTrue(iter.hasNext());
iter.next();
// below line should not affect remove
assertFalse(iter.hasNext());
iter.remove();
assertTrue("Expect empty but have entry: " + map, map.isEmpty());
}
@SuppressWarnings("unused")
private static void gc() {
try {