ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/AbstractMap.java
Revision: 1.1
Committed: Fri Dec 31 13:00:33 2004 UTC (19 years, 4 months ago) by dl
Branch: MAIN
Log Message:
Add AbstractMap.SimpleImmutableEntry; make SimpleEntry public

File Contents

# Content
1 /*
2 * %W% %E%
3 *
4 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6 */
7
8 package java.util;
9 import java.util.Map.Entry;
10
11 /**
12 * This class provides a skeletal implementation of the <tt>Map</tt>
13 * interface, to minimize the effort required to implement this interface. <p>
14 *
15 * To implement an unmodifiable map, the programmer needs only to extend this
16 * class and provide an implementation for the <tt>entrySet</tt> method, which
17 * returns a set-view of the map's mappings. Typically, the returned set
18 * will, in turn, be implemented atop <tt>AbstractSet</tt>. This set should
19 * not support the <tt>add</tt> or <tt>remove</tt> methods, and its iterator
20 * should not support the <tt>remove</tt> method.<p>
21 *
22 * To implement a modifiable map, the programmer must additionally override
23 * this class's <tt>put</tt> method (which otherwise throws an
24 * <tt>UnsupportedOperationException</tt>), and the iterator returned by
25 * <tt>entrySet().iterator()</tt> must additionally implement its
26 * <tt>remove</tt> method.<p>
27 *
28 * The programmer should generally provide a void (no argument) and map
29 * constructor, as per the recommendation in the <tt>Map</tt> interface
30 * specification.<p>
31 *
32 * The documentation for each non-abstract methods in this class describes its
33 * implementation in detail. Each of these methods may be overridden if the
34 * map being implemented admits a more efficient implementation.<p>
35 *
36 * This class is a member of the
37 * <a href="{@docRoot}/../guide/collections/index.html">
38 * Java Collections Framework</a>.
39 *
40 * @author Josh Bloch
41 * @author Neal Gafter
42 * @version %I%, %G%
43 * @see Map
44 * @see Collection
45 * @since 1.2
46 */
47
48 public abstract class AbstractMap<K,V> implements Map<K,V> {
49 /**
50 * Sole constructor. (For invocation by subclass constructors, typically
51 * implicit.)
52 */
53 protected AbstractMap() {
54 }
55
56 // Query Operations
57
58 /**
59 * Returns the number of key-value mappings in this map. If the map
60 * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
61 * <tt>Integer.MAX_VALUE</tt>.<p>
62 *
63 * This implementation returns <tt>entrySet().size()</tt>.
64 *
65 * @return the number of key-value mappings in this map.
66 */
67 public int size() {
68 return entrySet().size();
69 }
70
71 /**
72 * Returns <tt>true</tt> if this map contains no key-value mappings. <p>
73 *
74 * This implementation returns <tt>size() == 0</tt>.
75 *
76 * @return <tt>true</tt> if this map contains no key-value mappings.
77 */
78 public boolean isEmpty() {
79 return size() == 0;
80 }
81
82 /**
83 * Returns <tt>true</tt> if this map maps one or more keys to this value.
84 * More formally, returns <tt>true</tt> if and only if this map contains
85 * at least one mapping to a value <tt>v</tt> such that <tt>(value==null ?
86 * v==null : value.equals(v))</tt>. This operation will probably require
87 * time linear in the map size for most implementations of map.<p>
88 *
89 * This implementation iterates over entrySet() searching for an entry
90 * with the specified value. If such an entry is found, <tt>true</tt> is
91 * returned. If the iteration terminates without finding such an entry,
92 * <tt>false</tt> is returned. Note that this implementation requires
93 * linear time in the size of the map.
94 *
95 * @param value value whose presence in this map is to be tested.
96 *
97 * @return <tt>true</tt> if this map maps one or more keys to this value.
98 */
99 public boolean containsValue(Object value) {
100 Iterator<Entry<K,V>> i = entrySet().iterator();
101 if (value==null) {
102 while (i.hasNext()) {
103 Entry<K,V> e = i.next();
104 if (e.getValue()==null)
105 return true;
106 }
107 } else {
108 while (i.hasNext()) {
109 Entry<K,V> e = i.next();
110 if (value.equals(e.getValue()))
111 return true;
112 }
113 }
114 return false;
115 }
116
117 /**
118 * Returns <tt>true</tt> if this map contains a mapping for the specified
119 * key. <p>
120 *
121 * This implementation iterates over <tt>entrySet()</tt> searching for an
122 * entry with the specified key. If such an entry is found, <tt>true</tt>
123 * is returned. If the iteration terminates without finding such an
124 * entry, <tt>false</tt> is returned. Note that this implementation
125 * requires linear time in the size of the map; many implementations will
126 * override this method.
127 *
128 * @param key key whose presence in this map is to be tested.
129 * @return <tt>true</tt> if this map contains a mapping for the specified
130 * key.
131 *
132 * @throws NullPointerException if the key is <tt>null</tt> and this map
133 * does not permit <tt>null</tt> keys.
134 */
135 public boolean containsKey(Object key) {
136 Iterator<Map.Entry<K,V>> i = entrySet().iterator();
137 if (key==null) {
138 while (i.hasNext()) {
139 Entry<K,V> e = i.next();
140 if (e.getKey()==null)
141 return true;
142 }
143 } else {
144 while (i.hasNext()) {
145 Entry<K,V> e = i.next();
146 if (key.equals(e.getKey()))
147 return true;
148 }
149 }
150 return false;
151 }
152
153 /**
154 * Returns the value to which this map maps the specified key. Returns
155 * <tt>null</tt> if the map contains no mapping for this key. A return
156 * value of <tt>null</tt> does not <i>necessarily</i> indicate that the
157 * map contains no mapping for the key; it's also possible that the map
158 * explicitly maps the key to <tt>null</tt>. The containsKey operation
159 * may be used to distinguish these two cases. <p>
160 *
161 * This implementation iterates over <tt>entrySet()</tt> searching for an
162 * entry with the specified key. If such an entry is found, the entry's
163 * value is returned. If the iteration terminates without finding such an
164 * entry, <tt>null</tt> is returned. Note that this implementation
165 * requires linear time in the size of the map; many implementations will
166 * override this method.
167 *
168 * @param key key whose associated value is to be returned.
169 * @return the value to which this map maps the specified key.
170 *
171 * @throws NullPointerException if the key is <tt>null</tt> and this map
172 * does not permit <tt>null</tt> keys.
173 *
174 * @see #containsKey(Object)
175 */
176 public V get(Object key) {
177 Iterator<Entry<K,V>> i = entrySet().iterator();
178 if (key==null) {
179 while (i.hasNext()) {
180 Entry<K,V> e = i.next();
181 if (e.getKey()==null)
182 return e.getValue();
183 }
184 } else {
185 while (i.hasNext()) {
186 Entry<K,V> e = i.next();
187 if (key.equals(e.getKey()))
188 return e.getValue();
189 }
190 }
191 return null;
192 }
193
194
195 // Modification Operations
196
197 /**
198 * Associates the specified value with the specified key in this map
199 * (optional operation). If the map previously contained a mapping for
200 * this key, the old value is replaced.<p>
201 *
202 * This implementation always throws an
203 * <tt>UnsupportedOperationException</tt>.
204 *
205 * @param key key with which the specified value is to be associated.
206 * @param value value to be associated with the specified key.
207 *
208 * @return previous value associated with specified key, or <tt>null</tt>
209 * if there was no mapping for key. (A <tt>null</tt> return can
210 * also indicate that the map previously associated <tt>null</tt>
211 * with the specified key, if the implementation supports
212 * <tt>null</tt> values.)
213 *
214 * @throws UnsupportedOperationException if the <tt>put</tt> operation is
215 * not supported by this map.
216 *
217 * @throws ClassCastException if the class of the specified key or value
218 * prevents it from being stored in this map.
219 *
220 * @throws IllegalArgumentException if some aspect of this key or value *
221 * prevents it from being stored in this map.
222 *
223 * @throws NullPointerException if this map does not permit <tt>null</tt>
224 * keys or values, and the specified key or value is
225 * <tt>null</tt>.
226 */
227 public V put(K key, V value) {
228 throw new UnsupportedOperationException();
229 }
230
231 /**
232 * Removes the mapping for this key from this map if present (optional
233 * operation). <p>
234 *
235 * This implementation iterates over <tt>entrySet()</tt> searching for an
236 * entry with the specified key. If such an entry is found, its value is
237 * obtained with its <tt>getValue</tt> operation, the entry is removed
238 * from the Collection (and the backing map) with the iterator's
239 * <tt>remove</tt> operation, and the saved value is returned. If the
240 * iteration terminates without finding such an entry, <tt>null</tt> is
241 * returned. Note that this implementation requires linear time in the
242 * size of the map; many implementations will override this method.<p>
243 *
244 * Note that this implementation throws an
245 * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt> iterator
246 * does not support the <tt>remove</tt> method and this map contains a
247 * mapping for the specified key.
248 *
249 * @param key key whose mapping is to be removed from the map.
250 * @return previous value associated with specified key, or <tt>null</tt>
251 * if there was no entry for key. (A <tt>null</tt> return can
252 * also indicate that the map previously associated <tt>null</tt>
253 * with the specified key, if the implementation supports
254 * <tt>null</tt> values.)
255 * @throws UnsupportedOperationException if the <tt>remove</tt> operation
256 * is not supported by this map.
257 */
258 public V remove(Object key) {
259 Iterator<Entry<K,V>> i = entrySet().iterator();
260 Entry<K,V> correctEntry = null;
261 if (key==null) {
262 while (correctEntry==null && i.hasNext()) {
263 Entry<K,V> e = i.next();
264 if (e.getKey()==null)
265 correctEntry = e;
266 }
267 } else {
268 while (correctEntry==null && i.hasNext()) {
269 Entry<K,V> e = i.next();
270 if (key.equals(e.getKey()))
271 correctEntry = e;
272 }
273 }
274
275 V oldValue = null;
276 if (correctEntry !=null) {
277 oldValue = correctEntry.getValue();
278 i.remove();
279 }
280 return oldValue;
281 }
282
283
284 // Bulk Operations
285
286 /**
287 * Copies all of the mappings from the specified map to this map
288 * (optional operation). These mappings will replace any mappings that
289 * this map had for any of the keys currently in the specified map.<p>
290 *
291 * This implementation iterates over the specified map's
292 * <tt>entrySet()</tt> collection, and calls this map's <tt>put</tt>
293 * operation once for each entry returned by the iteration.<p>
294 *
295 * Note that this implementation throws an
296 * <tt>UnsupportedOperationException</tt> if this map does not support
297 * the <tt>put</tt> operation and the specified map is nonempty.
298 *
299 * @param t mappings to be stored in this map.
300 *
301 * @throws UnsupportedOperationException if the <tt>putAll</tt> operation
302 * is not supported by this map.
303 *
304 * @throws ClassCastException if the class of a key or value in the
305 * specified map prevents it from being stored in this map.
306 *
307 * @throws IllegalArgumentException if some aspect of a key or value in
308 * the specified map prevents it from being stored in this map.
309 * @throws NullPointerException if the specified map is <tt>null</tt>, or if
310 * this map does not permit <tt>null</tt> keys or values, and the
311 * specified map contains <tt>null</tt> keys or values.
312 */
313 public void putAll(Map<? extends K, ? extends V> t) {
314 Iterator<? extends Entry<? extends K, ? extends V>> i = t.entrySet().iterator();
315 while (i.hasNext()) {
316 Entry<? extends K, ? extends V> e = i.next();
317 put(e.getKey(), e.getValue());
318 }
319 }
320
321 /**
322 * Removes all mappings from this map (optional operation). <p>
323 *
324 * This implementation calls <tt>entrySet().clear()</tt>.
325 *
326 * Note that this implementation throws an
327 * <tt>UnsupportedOperationException</tt> if the <tt>entrySet</tt>
328 * does not support the <tt>clear</tt> operation.
329 *
330 * @throws UnsupportedOperationException clear is not supported
331 * by this map.
332 */
333 public void clear() {
334 entrySet().clear();
335 }
336
337
338 // Views
339
340 /**
341 * Each of these fields are initialized to contain an instance of the
342 * appropriate view the first time this view is requested. The views are
343 * stateless, so there's no reason to create more than one of each.
344 */
345 transient volatile Set<K> keySet = null;
346 transient volatile Collection<V> values = null;
347
348 /**
349 * Returns a Set view of the keys contained in this map. The Set is
350 * backed by the map, so changes to the map are reflected in the Set,
351 * and vice-versa. (If the map is modified while an iteration over
352 * the Set is in progress, the results of the iteration are undefined.)
353 * The Set supports element removal, which removes the corresponding entry
354 * from the map, via the Iterator.remove, Set.remove, removeAll
355 * retainAll, and clear operations. It does not support the add or
356 * addAll operations.<p>
357 *
358 * This implementation returns a Set that subclasses
359 * AbstractSet. The subclass's iterator method returns a "wrapper
360 * object" over this map's entrySet() iterator. The size method delegates
361 * to this map's size method and the contains method delegates to this
362 * map's containsKey method.<p>
363 *
364 * The Set is created the first time this method is called,
365 * and returned in response to all subsequent calls. No synchronization
366 * is performed, so there is a slight chance that multiple calls to this
367 * method will not all return the same Set.
368 *
369 * @return a Set view of the keys contained in this map.
370 */
371 public Set<K> keySet() {
372 if (keySet == null) {
373 keySet = new AbstractSet<K>() {
374 public Iterator<K> iterator() {
375 return new Iterator<K>() {
376 private Iterator<Entry<K,V>> i = entrySet().iterator();
377
378 public boolean hasNext() {
379 return i.hasNext();
380 }
381
382 public K next() {
383 return i.next().getKey();
384 }
385
386 public void remove() {
387 i.remove();
388 }
389 };
390 }
391
392 public int size() {
393 return AbstractMap.this.size();
394 }
395
396 public boolean contains(Object k) {
397 return AbstractMap.this.containsKey(k);
398 }
399 };
400 }
401 return keySet;
402 }
403
404 /**
405 * Returns a collection view of the values contained in this map. The
406 * collection is backed by the map, so changes to the map are reflected in
407 * the collection, and vice-versa. (If the map is modified while an
408 * iteration over the collection is in progress, the results of the
409 * iteration are undefined.) The collection supports element removal,
410 * which removes the corresponding entry from the map, via the
411 * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
412 * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt> operations.
413 * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.<p>
414 *
415 * This implementation returns a collection that subclasses abstract
416 * collection. The subclass's iterator method returns a "wrapper object"
417 * over this map's <tt>entrySet()</tt> iterator. The size method
418 * delegates to this map's size method and the contains method delegates
419 * to this map's containsValue method.<p>
420 *
421 * The collection is created the first time this method is called, and
422 * returned in response to all subsequent calls. No synchronization is
423 * performed, so there is a slight chance that multiple calls to this
424 * method will not all return the same Collection.
425 *
426 * @return a collection view of the values contained in this map.
427 */
428 public Collection<V> values() {
429 if (values == null) {
430 values = new AbstractCollection<V>() {
431 public Iterator<V> iterator() {
432 return new Iterator<V>() {
433 private Iterator<Entry<K,V>> i = entrySet().iterator();
434
435 public boolean hasNext() {
436 return i.hasNext();
437 }
438
439 public V next() {
440 return i.next().getValue();
441 }
442
443 public void remove() {
444 i.remove();
445 }
446 };
447 }
448
449 public int size() {
450 return AbstractMap.this.size();
451 }
452
453 public boolean contains(Object v) {
454 return AbstractMap.this.containsValue(v);
455 }
456 };
457 }
458 return values;
459 }
460
461 /**
462 * Returns a set view of the mappings contained in this map. Each element
463 * in this set is a Map.Entry. The set is backed by the map, so changes
464 * to the map are reflected in the set, and vice-versa. (If the map is
465 * modified while an iteration over the set is in progress, the results of
466 * the iteration are undefined.) The set supports element removal, which
467 * removes the corresponding entry from the map, via the
468 * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, <tt>removeAll</tt>,
469 * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not support
470 * the <tt>add</tt> or <tt>addAll</tt> operations.
471 *
472 * @return a set view of the mappings contained in this map.
473 */
474 public abstract Set<Entry<K,V>> entrySet();
475
476
477 // Comparison and hashing
478
479 /**
480 * Compares the specified object with this map for equality. Returns
481 * <tt>true</tt> if the given object is also a map and the two maps
482 * represent the same mappings. More formally, two maps <tt>t1</tt> and
483 * <tt>t2</tt> represent the same mappings if
484 * <tt>t1.keySet().equals(t2.keySet())</tt> and for every key <tt>k</tt>
485 * in <tt>t1.keySet()</tt>, <tt> (t1.get(k)==null ? t2.get(k)==null :
486 * t1.get(k).equals(t2.get(k))) </tt>. This ensures that the
487 * <tt>equals</tt> method works properly across different implementations
488 * of the map interface.<p>
489 *
490 * This implementation first checks if the specified object is this map;
491 * if so it returns <tt>true</tt>. Then, it checks if the specified
492 * object is a map whose size is identical to the size of this set; if
493 * not, it returns <tt>false</tt>. If so, it iterates over this map's
494 * <tt>entrySet</tt> collection, and checks that the specified map
495 * contains each mapping that this map contains. If the specified map
496 * fails to contain such a mapping, <tt>false</tt> is returned. If the
497 * iteration completes, <tt>true</tt> is returned.
498 *
499 * @param o object to be compared for equality with this map.
500 * @return <tt>true</tt> if the specified object is equal to this map.
501 */
502 public boolean equals(Object o) {
503 if (o == this)
504 return true;
505
506 if (!(o instanceof Map))
507 return false;
508 Map<K,V> t = (Map<K,V>) o;
509 if (t.size() != size())
510 return false;
511
512 try {
513 Iterator<Entry<K,V>> i = entrySet().iterator();
514 while (i.hasNext()) {
515 Entry<K,V> e = i.next();
516 K key = e.getKey();
517 V value = e.getValue();
518 if (value == null) {
519 if (!(t.get(key)==null && t.containsKey(key)))
520 return false;
521 } else {
522 if (!value.equals(t.get(key)))
523 return false;
524 }
525 }
526 } catch(ClassCastException unused) {
527 return false;
528 } catch(NullPointerException unused) {
529 return false;
530 }
531
532 return true;
533 }
534
535 /**
536 * Returns the hash code value for this map. The hash code of a map is
537 * defined to be the sum of the hash codes of each entry in the map's
538 * <tt>entrySet()</tt> view. This ensures that <tt>t1.equals(t2)</tt>
539 * implies that <tt>t1.hashCode()==t2.hashCode()</tt> for any two maps
540 * <tt>t1</tt> and <tt>t2</tt>, as required by the general contract of
541 * Object.hashCode.<p>
542 *
543 * This implementation iterates over <tt>entrySet()</tt>, calling
544 * <tt>hashCode</tt> on each element (entry) in the Collection, and adding
545 * up the results.
546 *
547 * @return the hash code value for this map.
548 * @see Map.Entry#hashCode()
549 * @see Object#hashCode()
550 * @see Object#equals(Object)
551 * @see Set#equals(Object)
552 */
553 public int hashCode() {
554 int h = 0;
555 Iterator<Entry<K,V>> i = entrySet().iterator();
556 while (i.hasNext())
557 h += i.next().hashCode();
558 return h;
559 }
560
561 /**
562 * Returns a string representation of this map. The string representation
563 * consists of a list of key-value mappings in the order returned by the
564 * map's <tt>entrySet</tt> view's iterator, enclosed in braces
565 * (<tt>"{}"</tt>). Adjacent mappings are separated by the characters
566 * <tt>", "</tt> (comma and space). Each key-value mapping is rendered as
567 * the key followed by an equals sign (<tt>"="</tt>) followed by the
568 * associated value. Keys and values are converted to strings as by
569 * <tt>String.valueOf(Object)</tt>.<p>
570 *
571 * This implementation creates an empty string buffer, appends a left
572 * brace, and iterates over the map's <tt>entrySet</tt> view, appending
573 * the string representation of each <tt>map.entry</tt> in turn. After
574 * appending each entry except the last, the string <tt>", "</tt> is
575 * appended. Finally a right brace is appended. A string is obtained
576 * from the stringbuffer, and returned.
577 *
578 * @return a String representation of this map.
579 */
580 public String toString() {
581 StringBuffer buf = new StringBuffer();
582 buf.append("{");
583
584 Iterator<Entry<K,V>> i = entrySet().iterator();
585 boolean hasNext = i.hasNext();
586 while (hasNext) {
587 Entry<K,V> e = i.next();
588 K key = e.getKey();
589 V value = e.getValue();
590 if (key == this)
591 buf.append("(this Map)");
592 else
593 buf.append(key);
594 buf.append("=");
595 if (value == this)
596 buf.append("(this Map)");
597 else
598 buf.append(value);
599 hasNext = i.hasNext();
600 if (hasNext)
601 buf.append(", ");
602 }
603
604 buf.append("}");
605 return buf.toString();
606 }
607
608 /**
609 * Returns a shallow copy of this <tt>AbstractMap</tt> instance: the keys
610 * and values themselves are not cloned.
611 *
612 * @return a shallow copy of this map.
613 */
614 protected Object clone() throws CloneNotSupportedException {
615 AbstractMap<K,V> result = (AbstractMap<K,V>)super.clone();
616 result.keySet = null;
617 result.values = null;
618 return result;
619 }
620
621 /**
622 * Utility method for SimpleEntry and SimpleImmutableEntry.
623 * Test for equality, checking for nulls.
624 */
625 private static boolean eq(Object o1, Object o2) {
626 return (o1 == null ? o2 == null : o1.equals(o2));
627 }
628
629 // Implementation Note: SimpleEntry and SimpleImmutableEntry
630 // are distinct unrelated classes, even though they share
631 // some code. Since you can't add or subtract final-ness
632 // of a field in a subclass, they can't share represenations,
633 // and the amount of duplicated code is too small to warrant
634 // exposing a common abstract class.
635
636
637 /**
638 * An Entry maintaining a key and a value. The value may be
639 * changed using the <tt>setValue</tt> method. This class
640 * facilitates the process of building custom map
641 * implementations. For example, it may be convenient to return
642 * arrays of <tt>SimpleEntry</tt> instances in method
643 * <tt>Map.entrySet().toArray</tt>
644 */
645 public static class SimpleEntry<K,V> implements Entry<K,V> {
646 private K key;
647 private V value;
648
649 /**
650 * Creates an entry representing a mapping from the specified
651 * key to the specified value.
652 *
653 * @param key the key represented by this entry
654 * @param value the value represented by this entry
655 */
656 public SimpleEntry(K key, V value) {
657 this.key = key;
658 this.value = value;
659 }
660
661 /**
662 * Creates an entry representing the same mapping as the
663 * specified entry.
664 *
665 * @param entry the entry to copy.
666 */
667 public SimpleEntry(Entry<K,V> entry) {
668 this.key = entry.getKey();
669 this.value = entry.getValue();
670 }
671
672 /**
673 * Returns the key corresponding to this entry.
674 *
675 * @return the key corresponding to this entry.
676 */
677 public K getKey() {
678 return key;
679 }
680
681 /**
682 * Returns the value corresponding to this entry.
683 *
684 * @return the value corresponding to this entry.
685 */
686 public V getValue() {
687 return value;
688 }
689
690 /**
691 * Replaces the value corresponding to this entry with the specified
692 * value.
693 *
694 * @param value new value to be stored in this entry.
695 * @return old value corresponding to the entry.
696 */
697 public V setValue(V value) {
698 V oldValue = this.value;
699 this.value = value;
700 return oldValue;
701 }
702
703 public boolean equals(Object o) {
704 if (!(o instanceof Map.Entry))
705 return false;
706 Map.Entry e = (Map.Entry)o;
707 return eq(key, e.getKey()) && eq(value, e.getValue());
708 }
709
710 public int hashCode() {
711 return ((key == null) ? 0 : key.hashCode()) ^
712 ((value == null) ? 0 : value.hashCode());
713 }
714
715 /**
716 * Returns a String representation of this map entry. This
717 * implementation returns the string representation of this
718 * entry's key followed by the equals character ("<tt>=</tt>")
719 * followed by the string representation of this entry's value.
720 *
721 * @return a String representation of this map entry.
722 */
723 public String toString() {
724 return key + "=" + value;
725 }
726
727 }
728
729 /**
730 * An Entry maintaining an immutable key and value, This class
731 * does not support method <tt>setValue</tt>. This class may be
732 * convenient in methods that return thread-safe snapshots of
733 * key-value mappings.
734 */
735 public static class SimpleImmutableEntry<K,V> implements Entry<K,V> {
736 private final K key;
737 private final V value;
738
739 /**
740 * Creates an entry representing a mapping from the specified
741 * key to the specified value.
742 *
743 * @param key the key represented by this entry
744 * @param value the value represented by this entry
745 */
746 public SimpleImmutableEntry(K key, V value) {
747 this.key = key;
748 this.value = value;
749 }
750
751 /**
752 * Creates an entry representing the same mapping as the
753 * specified entry.
754 *
755 * @param entry the entry to copy.
756 */
757 public SimpleImmutableEntry(Entry<K,V> entry) {
758 this.key = entry.getKey();
759 this.value = entry.getValue();
760 }
761
762 /**
763 * Returns the key corresponding to this entry.
764 *
765 * @return the key corresponding to this entry.
766 */
767 public K getKey() {
768 return key;
769 }
770
771 /**
772 * Returns the value corresponding to this entry.
773 *
774 * @return the value corresponding to this entry.
775 */
776 public V getValue() {
777 return value;
778 }
779
780 /**
781 * Replaces the value corresponding to this entry with the specified
782 * value (optional operation). This implementation simply throws
783 * <tt>UnsupportedOperationException</tt>, as this class implements
784 * an <i>immutable</i> map entry.
785 *
786 * @param value new value to be stored in this entry.
787 * @return (Does not return)
788 * @throws UnsupportedOperationException always
789 */
790 public V setValue(V value) {
791 throw new UnsupportedOperationException();
792 }
793
794 public boolean equals(Object o) {
795 if (!(o instanceof Map.Entry))
796 return false;
797 Map.Entry e = (Map.Entry)o;
798 return eq(key, e.getKey()) && eq(value, e.getValue());
799 }
800
801 public int hashCode() {
802 return ((key == null) ? 0 : key.hashCode()) ^
803 ((value == null) ? 0 : value.hashCode());
804 }
805
806 /**
807 * Returns a String representation of this map entry. This
808 * implementation returns the string representation of this
809 * entry's key followed by the equals character ("<tt>=</tt>")
810 * followed by the string representation of this entry's value.
811 *
812 * @return a String representation of this map entry.
813 */
814 public String toString() {
815 return key + "=" + value;
816 }
817
818 }
819
820 }