8038146: Clarify Map.Entry's connection to the underlying map

Reviewed-by: alanb
This commit is contained in:
Stuart Marks 2023-01-20 16:33:48 +00:00
parent b2d3622115
commit c6d5600396
4 changed files with 74 additions and 36 deletions

View file

@ -590,7 +590,8 @@ public abstract class AbstractMap<K,V> implements Map<K,V> {
/** /**
* An Entry maintaining a key and a value. The value may be * An Entry maintaining a key and a value. The value may be
* changed using the {@code setValue} method. Instances of * changed using the {@code setValue} method. Instances of
* this class are not associated with any map's entry-set view. * this class are not associated with any map nor with any
* map's entry-set view.
* *
* @apiNote * @apiNote
* This class facilitates the process of building custom map * This class facilitates the process of building custom map
@ -730,7 +731,8 @@ public abstract class AbstractMap<K,V> implements Map<K,V> {
/** /**
* An unmodifiable Entry maintaining a key and a value. This class * An unmodifiable Entry maintaining a key and a value. This class
* does not support the {@code setValue} method. Instances of * does not support the {@code setValue} method. Instances of
* this class are not associated with any map's entry-set view. * this class are not associated with any map nor with any map's
* entry-set view.
* *
* @apiNote * @apiNote
* Instances of this class are not necessarily immutable, as the key * Instances of this class are not necessarily immutable, as the key

View file

@ -390,25 +390,48 @@ public interface Map<K, V> {
* implemented. The Entry may be independent of any map, or it may represent * implemented. The Entry may be independent of any map, or it may represent
* an entry of the entry-set view of a map. * an entry of the entry-set view of a map.
* <p> * <p>
* Instances of the {@code Map.Entry} interface may be obtained by iterating * An Entry maintains a connection to its underlying map if the Entry was obtained by
* the entry-set view of a map. These instances maintain a connection to the * iterating the {@link Map#entrySet} view of a map, either explicitly by using an
* original, backing map. This connection to the backing map is valid * {@link Iterator} or implicitly via the enhanced {@code for} statement. This connection
* <i>only</i> for the duration of iteration over the entry-set view. * to the backing map is valid <i>only</i> during iteration of the entry-set view. During
* During iteration of the entry-set view, if supported by the backing map, * the iteration, if supported by the backing map, a change to an Entry's value via
* a change to a {@code Map.Entry}'s value via the * the {@link Map.Entry#setValue setValue} method will be visible in the backing map.
* {@link Map.Entry#setValue setValue} method will be visible in the backing map. * The behavior of such an Entry is undefined outside of iteration of the map's entry-set
* The behavior of such a {@code Map.Entry} instance is undefined outside of * view. It is also undefined if the backing map has been modified after the Entry was
* iteration of the map's entry-set view. It is also undefined if the backing * returned by the iterator, except through the {@code setValue} method. In addition,
* map has been modified after the {@code Map.Entry} was returned by the
* iterator, except through the {@code Map.Entry.setValue} method. In particular,
* a change to the value of a mapping in the backing map might or might not be * a change to the value of a mapping in the backing map might or might not be
* visible in the corresponding {@code Map.Entry} element of the entry-set view. * visible in the corresponding Entry of the entry-set view.
* <p>
* An Entry may also be obtained from a map's entry-set view by other means, for
* example, using the
* {@link Set#parallelStream parallelStream},
* {@link Set#stream stream},
* {@link Set#spliterator spliterator} methods,
* any of the
* {@link Set#toArray toArray} overloads,
* or by copying the entry-set view into another collection. It is unspecified whether
* the obtained Entry instances are connected to the underlying map, whether changes
* to such an Entry will affect the underlying the map and vice-versa, and whether
* such an Entry supports the optional {@link Map.Entry#setValue setValue} method.
* <p>
* In addition, an Entry may be obtained directly from a map, for example via calls
* to methods directly on the {@link NavigableMap} interface. An entry thus obtained
* is generally not connected to the map and is an unmodifiable snapshot of the mapping
* as of the time of the call. Such an Entry also does not generally support the
* {@code setValue} method.
* <p>
* An Entry obtained by direct construction of the {@link AbstractMap.SimpleEntry}
* or {@link AbstractMap.SimpleImmutableEntry} classes or from a call to the
* {@link Map#entry Map.entry} or {@link Map.Entry#copyOf Map.Entry.copyOf} methods
* is not connected to any map.
* *
* @apiNote * @apiNote
* It is possible to create a {@code Map.Entry} instance that is disconnected * The exact behavior of Entry instances obtained from a map's entry-set view other than
* from a backing map by using the {@link Map.Entry#copyOf copyOf} method. For example, * via iteration varies across different map implementations; some are connected to the
* the following creates a snapshot of a map's entries that is guaranteed not to * backing map, and some are not. To guarantee that an Entry is disconnected from its
* change even if the original map is modified: * backing map, use the {@link Map.Entry#copyOf copyOf} method. For example, the following
* creates a snapshot of a map's entries that is guaranteed not to change even if the
* original map is modified:
* <pre> {@code * <pre> {@code
* var entries = map.entrySet().stream().map(Map.Entry::copyOf).toList() * var entries = map.entrySet().stream().map(Map.Entry::copyOf).toList()
* }</pre> * }</pre>

View file

@ -66,12 +66,18 @@ package java.util;
* {@link #pollLastEntry} that return and/or remove the least and * {@link #pollLastEntry} that return and/or remove the least and
* greatest mappings, if any exist, else returning {@code null}. * greatest mappings, if any exist, else returning {@code null}.
* *
* <p>Implementations of entry-returning methods are expected to * <p>The methods
* return {@code Map.Entry} pairs representing snapshots of mappings * {@link #ceilingEntry},
* at the time they were produced, and thus generally do <em>not</em> * {@link #firstEntry},
* support the optional {@code Entry.setValue} method. Note however * {@link #floorEntry},
* that it is possible to change mappings in the associated map using * {@link #higherEntry},
* method {@code put}. * {@link #lastEntry},
* {@link #lowerEntry},
* {@link #pollFirstEntry}, and
* {@link #pollLastEntry}
* return {@link Map.Entry} instances that represent snapshots of mappings as
* of the time of the call. They do <em>not</em> support mutation of the
* underlying map via the optional {@link Map.Entry#setValue setValue} method.
* *
* <p>Methods * <p>Methods
* {@link #subMap(Object, Object) subMap(K, K)}, * {@link #subMap(Object, Object) subMap(K, K)},

View file

@ -86,11 +86,18 @@ import java.util.function.Function;
* exception for its correctness: <em>the fail-fast behavior of iterators * exception for its correctness: <em>the fail-fast behavior of iterators
* should be used only to detect bugs.</em> * should be used only to detect bugs.</em>
* *
* <p>All {@code Map.Entry} pairs returned by methods in this class * <p>The methods
* and its views represent snapshots of mappings at the time they were * {@link #ceilingEntry},
* produced. They do <strong>not</strong> support the {@code Entry.setValue} * {@link #firstEntry},
* method. (Note however that it is possible to change mappings in the * {@link #floorEntry},
* associated map using {@code put}.) * {@link #higherEntry},
* {@link #lastEntry},
* {@link #lowerEntry},
* {@link #pollFirstEntry}, and
* {@link #pollLastEntry}
* return {@link Map.Entry} instances that represent snapshots of mappings as
* of the time of the call. They do <em>not</em> support mutation of the
* underlying map via the optional {@link Map.Entry#setValue setValue} method.
* *
* <p>This class is a member of the * <p>This class is a member of the
* <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework"> * <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
@ -419,7 +426,8 @@ public class TreeMap<K,V>
/** /**
* Gets the entry corresponding to the specified key; if no such entry * Gets the entry corresponding to the specified key; if no such entry
* exists, returns the entry for the greatest key less than the specified * exists, returns the entry for the greatest key less than the specified
* key; if no such entry exists, returns {@code null}. * key; if no such entry exists (i.e., the least key in the Tree is greater
* than the specified key), returns {@code null}.
*/ */
final Entry<K,V> getFloorEntry(K key) { final Entry<K,V> getFloorEntry(K key) {
Entry<K,V> p = root; Entry<K,V> p = root;
@ -450,10 +458,9 @@ public class TreeMap<K,V>
} }
/** /**
* Gets the entry for the least key greater than the specified * Returns the entry for the least key greater than the specified key; if
* key; if no such entry exists, returns the entry for the least * no such entry exists (i.e., the greatest key in the Tree is less than
* key greater than the specified key; if no such entry exists * or equal to the specified key), returns {@code null}.
* returns {@code null}.
*/ */
final Entry<K,V> getHigherEntry(K key) { final Entry<K,V> getHigherEntry(K key) {
Entry<K,V> p = root; Entry<K,V> p = root;
@ -484,7 +491,7 @@ public class TreeMap<K,V>
/** /**
* Returns the entry for the greatest key less than the specified key; if * Returns the entry for the greatest key less than the specified key; if
* no such entry exists (i.e., the least key in the Tree is greater than * no such entry exists (i.e., the least key in the Tree is greater than
* the specified key), returns {@code null}. * or equal to the specified key), returns {@code null}.
*/ */
final Entry<K,V> getLowerEntry(K key) { final Entry<K,V> getLowerEntry(K key) {
Entry<K,V> p = root; Entry<K,V> p = root;