ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/AbstractMap.java
Revision: 1.29
Committed: Thu Sep 30 01:53:03 2010 UTC (13 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.28: +1 -1 lines
Log Message:
optimize toString methods

File Contents

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