Skip to content

Commit c6d5600

Browse files
author
Stuart Marks
committed
8038146: Clarify Map.Entry's connection to the underlying map
Reviewed-by: alanb
1 parent b2d3622 commit c6d5600

File tree

4 files changed

+74
-36
lines changed

4 files changed

+74
-36
lines changed

src/java.base/share/classes/java/util/AbstractMap.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,8 @@ private static boolean eq(Object o1, Object o2) {
590590
/**
591591
* An Entry maintaining a key and a value. The value may be
592592
* changed using the {@code setValue} method. Instances of
593-
* this class are not associated with any map's entry-set view.
593+
* this class are not associated with any map nor with any
594+
* map's entry-set view.
594595
*
595596
* @apiNote
596597
* This class facilitates the process of building custom map
@@ -730,7 +731,8 @@ public String toString() {
730731
/**
731732
* An unmodifiable Entry maintaining a key and a value. This class
732733
* does not support the {@code setValue} method. Instances of
733-
* this class are not associated with any map's entry-set view.
734+
* this class are not associated with any map nor with any map's
735+
* entry-set view.
734736
*
735737
* @apiNote
736738
* Instances of this class are not necessarily immutable, as the key

src/java.base/share/classes/java/util/Map.java

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -390,25 +390,48 @@ public interface Map<K, V> {
390390
* implemented. The Entry may be independent of any map, or it may represent
391391
* an entry of the entry-set view of a map.
392392
* <p>
393-
* Instances of the {@code Map.Entry} interface may be obtained by iterating
394-
* the entry-set view of a map. These instances maintain a connection to the
395-
* original, backing map. This connection to the backing map is valid
396-
* <i>only</i> for the duration of iteration over the entry-set view.
397-
* During iteration of the entry-set view, if supported by the backing map,
398-
* a change to a {@code Map.Entry}'s value via the
399-
* {@link Map.Entry#setValue setValue} method will be visible in the backing map.
400-
* The behavior of such a {@code Map.Entry} instance is undefined outside of
401-
* iteration of the map's entry-set view. It is also undefined if the backing
402-
* map has been modified after the {@code Map.Entry} was returned by the
403-
* iterator, except through the {@code Map.Entry.setValue} method. In particular,
393+
* An Entry maintains a connection to its underlying map if the Entry was obtained by
394+
* iterating the {@link Map#entrySet} view of a map, either explicitly by using an
395+
* {@link Iterator} or implicitly via the enhanced {@code for} statement. This connection
396+
* to the backing map is valid <i>only</i> during iteration of the entry-set view. During
397+
* the iteration, if supported by the backing map, a change to an Entry's value via
398+
* the {@link Map.Entry#setValue setValue} method will be visible in the backing map.
399+
* The behavior of such an Entry is undefined outside of iteration of the map's entry-set
400+
* view. It is also undefined if the backing map has been modified after the Entry was
401+
* returned by the iterator, except through the {@code setValue} method. In addition,
404402
* a change to the value of a mapping in the backing map might or might not be
405-
* visible in the corresponding {@code Map.Entry} element of the entry-set view.
403+
* visible in the corresponding Entry of the entry-set view.
404+
* <p>
405+
* An Entry may also be obtained from a map's entry-set view by other means, for
406+
* example, using the
407+
* {@link Set#parallelStream parallelStream},
408+
* {@link Set#stream stream},
409+
* {@link Set#spliterator spliterator} methods,
410+
* any of the
411+
* {@link Set#toArray toArray} overloads,
412+
* or by copying the entry-set view into another collection. It is unspecified whether
413+
* the obtained Entry instances are connected to the underlying map, whether changes
414+
* to such an Entry will affect the underlying the map and vice-versa, and whether
415+
* such an Entry supports the optional {@link Map.Entry#setValue setValue} method.
416+
* <p>
417+
* In addition, an Entry may be obtained directly from a map, for example via calls
418+
* to methods directly on the {@link NavigableMap} interface. An entry thus obtained
419+
* is generally not connected to the map and is an unmodifiable snapshot of the mapping
420+
* as of the time of the call. Such an Entry also does not generally support the
421+
* {@code setValue} method.
422+
* <p>
423+
* An Entry obtained by direct construction of the {@link AbstractMap.SimpleEntry}
424+
* or {@link AbstractMap.SimpleImmutableEntry} classes or from a call to the
425+
* {@link Map#entry Map.entry} or {@link Map.Entry#copyOf Map.Entry.copyOf} methods
426+
* is not connected to any map.
406427
*
407428
* @apiNote
408-
* It is possible to create a {@code Map.Entry} instance that is disconnected
409-
* from a backing map by using the {@link Map.Entry#copyOf copyOf} method. For example,
410-
* the following creates a snapshot of a map's entries that is guaranteed not to
411-
* change even if the original map is modified:
429+
* The exact behavior of Entry instances obtained from a map's entry-set view other than
430+
* via iteration varies across different map implementations; some are connected to the
431+
* backing map, and some are not. To guarantee that an Entry is disconnected from its
432+
* backing map, use the {@link Map.Entry#copyOf copyOf} method. For example, the following
433+
* creates a snapshot of a map's entries that is guaranteed not to change even if the
434+
* original map is modified:
412435
* <pre> {@code
413436
* var entries = map.entrySet().stream().map(Map.Entry::copyOf).toList()
414437
* }</pre>
@@ -581,7 +604,7 @@ public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? s
581604
*
582605
* @apiNote
583606
* An instance obtained from a map's entry-set view has a connection to that map.
584-
* The {@code copyOf} method may be used to create a {@code Map.Entry} instance,
607+
* The {@code copyOf} method may be used to create a {@code Map.Entry} instance,
585608
* containing the same key and value, that is independent of any map.
586609
*
587610
* @implNote

src/java.base/share/classes/java/util/NavigableMap.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,18 @@
6666
* {@link #pollLastEntry} that return and/or remove the least and
6767
* greatest mappings, if any exist, else returning {@code null}.
6868
*
69-
* <p>Implementations of entry-returning methods are expected to
70-
* return {@code Map.Entry} pairs representing snapshots of mappings
71-
* at the time they were produced, and thus generally do <em>not</em>
72-
* support the optional {@code Entry.setValue} method. Note however
73-
* that it is possible to change mappings in the associated map using
74-
* method {@code put}.
69+
* <p>The methods
70+
* {@link #ceilingEntry},
71+
* {@link #firstEntry},
72+
* {@link #floorEntry},
73+
* {@link #higherEntry},
74+
* {@link #lastEntry},
75+
* {@link #lowerEntry},
76+
* {@link #pollFirstEntry}, and
77+
* {@link #pollLastEntry}
78+
* return {@link Map.Entry} instances that represent snapshots of mappings as
79+
* of the time of the call. They do <em>not</em> support mutation of the
80+
* underlying map via the optional {@link Map.Entry#setValue setValue} method.
7581
*
7682
* <p>Methods
7783
* {@link #subMap(Object, Object) subMap(K, K)},

src/java.base/share/classes/java/util/TreeMap.java

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,18 @@
8686
* exception for its correctness: <em>the fail-fast behavior of iterators
8787
* should be used only to detect bugs.</em>
8888
*
89-
* <p>All {@code Map.Entry} pairs returned by methods in this class
90-
* and its views represent snapshots of mappings at the time they were
91-
* produced. They do <strong>not</strong> support the {@code Entry.setValue}
92-
* method. (Note however that it is possible to change mappings in the
93-
* associated map using {@code put}.)
89+
* <p>The methods
90+
* {@link #ceilingEntry},
91+
* {@link #firstEntry},
92+
* {@link #floorEntry},
93+
* {@link #higherEntry},
94+
* {@link #lastEntry},
95+
* {@link #lowerEntry},
96+
* {@link #pollFirstEntry}, and
97+
* {@link #pollLastEntry}
98+
* return {@link Map.Entry} instances that represent snapshots of mappings as
99+
* of the time of the call. They do <em>not</em> support mutation of the
100+
* underlying map via the optional {@link Map.Entry#setValue setValue} method.
94101
*
95102
* <p>This class is a member of the
96103
* <a href="{@docRoot}/java.base/java/util/package-summary.html#CollectionsFramework">
@@ -419,7 +426,8 @@ final Entry<K,V> getCeilingEntry(K key) {
419426
/**
420427
* Gets the entry corresponding to the specified key; if no such entry
421428
* exists, returns the entry for the greatest key less than the specified
422-
* key; if no such entry exists, returns {@code null}.
429+
* key; if no such entry exists (i.e., the least key in the Tree is greater
430+
* than the specified key), returns {@code null}.
423431
*/
424432
final Entry<K,V> getFloorEntry(K key) {
425433
Entry<K,V> p = root;
@@ -450,10 +458,9 @@ final Entry<K,V> getFloorEntry(K key) {
450458
}
451459

452460
/**
453-
* Gets the entry for the least key greater than the specified
454-
* key; if no such entry exists, returns the entry for the least
455-
* key greater than the specified key; if no such entry exists
456-
* returns {@code null}.
461+
* Returns the entry for the least key greater than the specified key; if
462+
* no such entry exists (i.e., the greatest key in the Tree is less than
463+
* or equal to the specified key), returns {@code null}.
457464
*/
458465
final Entry<K,V> getHigherEntry(K key) {
459466
Entry<K,V> p = root;
@@ -484,7 +491,7 @@ final Entry<K,V> getHigherEntry(K key) {
484491
/**
485492
* Returns the entry for the greatest key less than the specified key; if
486493
* no such entry exists (i.e., the least key in the Tree is greater than
487-
* the specified key), returns {@code null}.
494+
* or equal to the specified key), returns {@code null}.
488495
*/
489496
final Entry<K,V> getLowerEntry(K key) {
490497
Entry<K,V> p = root;

0 commit comments

Comments
 (0)