[COLLECTIONS-454] Fix findbugs warnings by returning independent Map.Entry objects from an entrySet() iterator in Flat3Map.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1476813 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ce86f3f8aa
commit
9ea429c977
|
@ -22,6 +22,11 @@
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<release version="4.0" date="TBA" description="Next release">
|
<release version="4.0" date="TBA" description="Next release">
|
||||||
|
<action issue="COLLECTIONS-454" dev="tn" type="update">
|
||||||
|
An iterator over a "Flat3Map#entrySet()" will now return
|
||||||
|
independent Map.Entry objects that will not change anymore when
|
||||||
|
the iterator progresses.
|
||||||
|
</action>
|
||||||
<action issue="COLLECTIONS-452" dev="tn" type="update">
|
<action issue="COLLECTIONS-452" dev="tn" type="update">
|
||||||
Change base package to org.apache.commons.collections4.
|
Change base package to org.apache.commons.collections4.
|
||||||
</action>
|
</action>
|
||||||
|
|
|
@ -713,9 +713,10 @@ public class Flat3Map<K, V> implements IterableMap<K, V>, Serializable, Cloneabl
|
||||||
/**
|
/**
|
||||||
* Gets the entrySet view of the map.
|
* Gets the entrySet view of the map.
|
||||||
* Changes made to the view affect this map.
|
* Changes made to the view affect this map.
|
||||||
* The Map Entry is not an independent object and changes as the
|
* <p>
|
||||||
* iterator progresses.
|
* NOTE: from 4.0, the returned Map Entry will be an independent object and will
|
||||||
* To simply iterate through the entries, use {@link #mapIterator()}.
|
* not change anymore as the iterator progresses. To avoid this additional object
|
||||||
|
* creation and simply iterate through the entries, use {@link #mapIterator()}.
|
||||||
*
|
*
|
||||||
* @return the entrySet view
|
* @return the entrySet view
|
||||||
*/
|
*/
|
||||||
|
@ -771,45 +772,35 @@ public class Flat3Map<K, V> implements IterableMap<K, V>, Serializable, Cloneabl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static abstract class EntryIterator<K, V> implements Map.Entry<K, V> {
|
static class FlatMapEntry<K, V> implements Map.Entry<K, V> {
|
||||||
private final Flat3Map<K, V> parent;
|
private final Flat3Map<K, V> parent;
|
||||||
private int nextIndex = 0;
|
private final int index;
|
||||||
protected boolean canRemove = false;
|
private volatile boolean removed;
|
||||||
|
|
||||||
|
public FlatMapEntry(final Flat3Map<K, V> parent, final int index) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.index = index;
|
||||||
|
this.removed = false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Flat3Map.EntryIterator.
|
* Used by the iterator that created this entry to indicate that
|
||||||
|
* {@link java.util.Iterator#remove()} has been called.
|
||||||
|
* <p>
|
||||||
|
* As a consequence, all subsequent call to {@link #getKey()},
|
||||||
|
* {@link #setValue(Object)} and {@link #getValue()} will fail.
|
||||||
|
*
|
||||||
|
* @param flag
|
||||||
*/
|
*/
|
||||||
public EntryIterator(final Flat3Map<K, V> parent) {
|
void setRemoved(final boolean flag) {
|
||||||
this.parent = parent;
|
this.removed = flag;
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
return nextIndex < parent.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map.Entry<K, V> nextEntry() {
|
|
||||||
if (hasNext() == false) {
|
|
||||||
throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
|
|
||||||
}
|
|
||||||
canRemove = true;
|
|
||||||
nextIndex++;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
if (canRemove == false) {
|
|
||||||
throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
|
|
||||||
}
|
|
||||||
parent.remove(getKey());
|
|
||||||
nextIndex--;
|
|
||||||
canRemove = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public K getKey() {
|
public K getKey() {
|
||||||
if (canRemove == false) {
|
if (removed) {
|
||||||
throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
|
throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
|
||||||
}
|
}
|
||||||
switch (nextIndex) {
|
switch (index) {
|
||||||
case 3:
|
case 3:
|
||||||
return parent.key3;
|
return parent.key3;
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -821,10 +812,10 @@ public class Flat3Map<K, V> implements IterableMap<K, V>, Serializable, Cloneabl
|
||||||
}
|
}
|
||||||
|
|
||||||
public V getValue() {
|
public V getValue() {
|
||||||
if (canRemove == false) {
|
if (removed) {
|
||||||
throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
|
throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
|
||||||
}
|
}
|
||||||
switch (nextIndex) {
|
switch (index) {
|
||||||
case 3:
|
case 3:
|
||||||
return parent.value3;
|
return parent.value3;
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -836,11 +827,11 @@ public class Flat3Map<K, V> implements IterableMap<K, V>, Serializable, Cloneabl
|
||||||
}
|
}
|
||||||
|
|
||||||
public V setValue(final V value) {
|
public V setValue(final V value) {
|
||||||
if (canRemove == false) {
|
if (removed) {
|
||||||
throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
|
throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
|
||||||
}
|
}
|
||||||
final V old = getValue();
|
final V old = getValue();
|
||||||
switch (nextIndex) {
|
switch (index) {
|
||||||
case 3:
|
case 3:
|
||||||
parent.value3 = value;
|
parent.value3 = value;
|
||||||
break;
|
break;
|
||||||
|
@ -853,24 +844,10 @@ public class Flat3Map<K, V> implements IterableMap<K, V>, Serializable, Cloneabl
|
||||||
}
|
}
|
||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EntrySetIterator and MapEntry
|
|
||||||
*/
|
|
||||||
static class EntrySetIterator<K, V> extends EntryIterator<K, V> implements Iterator<Map.Entry<K, V>> {
|
|
||||||
|
|
||||||
EntrySetIterator(final Flat3Map<K, V> parent) {
|
|
||||||
super(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map.Entry<K, V> next() {
|
|
||||||
return nextEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(final Object obj) {
|
public boolean equals(final Object obj) {
|
||||||
if (canRemove == false) {
|
if (removed) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (obj instanceof Map.Entry == false) {
|
if (obj instanceof Map.Entry == false) {
|
||||||
|
@ -885,7 +862,7 @@ public class Flat3Map<K, V> implements IterableMap<K, V>, Serializable, Cloneabl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
if (canRemove == false) {
|
if (removed) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
final Object key = getKey();
|
final Object key = getKey();
|
||||||
|
@ -896,11 +873,61 @@ public class Flat3Map<K, V> implements IterableMap<K, V>, Serializable, Cloneabl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (canRemove) {
|
if (!removed) {
|
||||||
return getKey() + "=" + getValue();
|
return getKey() + "=" + getValue();
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract class EntryIterator<K, V> {
|
||||||
|
private final Flat3Map<K, V> parent;
|
||||||
|
private int nextIndex = 0;
|
||||||
|
protected FlatMapEntry<K, V> currentEntry = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Flat3Map.EntryIterator.
|
||||||
|
*/
|
||||||
|
public EntryIterator(final Flat3Map<K, V> parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasNext() {
|
||||||
|
return nextIndex < parent.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map.Entry<K, V> nextEntry() {
|
||||||
|
if (!hasNext()) {
|
||||||
|
throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
|
||||||
|
}
|
||||||
|
currentEntry = new FlatMapEntry<K, V>(parent, ++nextIndex);
|
||||||
|
return currentEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
if (currentEntry == null) {
|
||||||
|
throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
|
||||||
|
}
|
||||||
|
currentEntry.setRemoved(true);
|
||||||
|
parent.remove(currentEntry.getKey());
|
||||||
|
nextIndex--;
|
||||||
|
currentEntry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EntrySetIterator and MapEntry
|
||||||
|
*/
|
||||||
|
static class EntrySetIterator<K, V> extends EntryIterator<K, V> implements Iterator<Map.Entry<K, V>> {
|
||||||
|
EntrySetIterator(final Flat3Map<K, V> parent) {
|
||||||
|
super(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map.Entry<K, V> next() {
|
||||||
|
return nextEntry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -973,8 +1000,7 @@ public class Flat3Map<K, V> implements IterableMap<K, V>, Serializable, Cloneabl
|
||||||
}
|
}
|
||||||
|
|
||||||
public K next() {
|
public K next() {
|
||||||
nextEntry();
|
return nextEntry().getKey();
|
||||||
return getKey();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1041,8 +1067,7 @@ public class Flat3Map<K, V> implements IterableMap<K, V>, Serializable, Cloneabl
|
||||||
}
|
}
|
||||||
|
|
||||||
public V next() {
|
public V next() {
|
||||||
nextEntry();
|
return nextEntry().getValue();
|
||||||
return getValue();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue