Home | History | Annotate | Download | only in util
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 
     18 package java.util;
     19 
     20 import java.io.Serializable;
     21 
     22 /**
     23  * A base class for {@code Map} implementations.
     24  *
     25  * <p>Subclasses that permit new mappings to be added must override {@link
     26  * #put}.
     27  *
     28  * <p>The default implementations of many methods are inefficient for large
     29  * maps. For example in the default implementation, each call to {@link #get}
     30  * performs a linear iteration of the entry set. Subclasses should override such
     31  * methods to improve their performance.
     32  *
     33  * @since 1.2
     34  */
     35 public abstract class AbstractMap<K, V> implements Map<K, V> {
     36 
     37     // Lazily initialized key set.
     38     Set<K> keySet;
     39 
     40     Collection<V> valuesCollection;
     41 
     42     /**
     43      * An immutable key-value mapping. Despite the name, this class is non-final
     44      * and its subclasses may be mutable.
     45      *
     46      * @since 1.6
     47      */
     48     public static class SimpleImmutableEntry<K, V>
     49             implements Map.Entry<K, V>, Serializable {
     50         private static final long serialVersionUID = 7138329143949025153L;
     51 
     52         private final K key;
     53         private final V value;
     54 
     55         public SimpleImmutableEntry(K theKey, V theValue) {
     56             key = theKey;
     57             value = theValue;
     58         }
     59 
     60         /**
     61          * Constructs an instance with the key and value of {@code copyFrom}.
     62          */
     63         public SimpleImmutableEntry(Map.Entry<? extends K, ? extends V> copyFrom) {
     64             key = copyFrom.getKey();
     65             value = copyFrom.getValue();
     66         }
     67 
     68         public K getKey() {
     69             return key;
     70         }
     71 
     72         public V getValue() {
     73             return value;
     74         }
     75 
     76         /**
     77          * This base implementation throws {@code UnsupportedOperationException}
     78          * always.
     79          */
     80         public V setValue(V object) {
     81             throw new UnsupportedOperationException();
     82         }
     83 
     84         @Override public boolean equals(Object object) {
     85             if (this == object) {
     86                 return true;
     87             }
     88             if (object instanceof Map.Entry) {
     89                 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
     90                 return (key == null ? entry.getKey() == null : key.equals(entry
     91                         .getKey()))
     92                         && (value == null ? entry.getValue() == null : value
     93                                 .equals(entry.getValue()));
     94             }
     95             return false;
     96         }
     97 
     98         @Override public int hashCode() {
     99             return (key == null ? 0 : key.hashCode())
    100                     ^ (value == null ? 0 : value.hashCode());
    101         }
    102 
    103         @Override public String toString() {
    104             return key + "=" + value;
    105         }
    106     }
    107 
    108     /**
    109      * A key-value mapping with mutable values.
    110      *
    111      * @since 1.6
    112      */
    113     public static class SimpleEntry<K, V>
    114             implements Map.Entry<K, V>, Serializable {
    115         private static final long serialVersionUID = -8499721149061103585L;
    116 
    117         private final K key;
    118         private V value;
    119 
    120         public SimpleEntry(K theKey, V theValue) {
    121             key = theKey;
    122             value = theValue;
    123         }
    124 
    125         /**
    126          * Constructs an instance with the key and value of {@code copyFrom}.
    127          */
    128         public SimpleEntry(Map.Entry<? extends K, ? extends V> copyFrom) {
    129             key = copyFrom.getKey();
    130             value = copyFrom.getValue();
    131         }
    132 
    133         public K getKey() {
    134             return key;
    135         }
    136 
    137         public V getValue() {
    138             return value;
    139         }
    140 
    141         public V setValue(V object) {
    142             V result = value;
    143             value = object;
    144             return result;
    145         }
    146 
    147         @Override public boolean equals(Object object) {
    148             if (this == object) {
    149                 return true;
    150             }
    151             if (object instanceof Map.Entry) {
    152                 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) object;
    153                 return (key == null ? entry.getKey() == null : key.equals(entry
    154                         .getKey()))
    155                         && (value == null ? entry.getValue() == null : value
    156                                 .equals(entry.getValue()));
    157             }
    158             return false;
    159         }
    160 
    161         @Override public int hashCode() {
    162             return (key == null ? 0 : key.hashCode())
    163                     ^ (value == null ? 0 : value.hashCode());
    164         }
    165 
    166         @Override public String toString() {
    167             return key + "=" + value;
    168         }
    169     }
    170 
    171     protected AbstractMap() {
    172     }
    173 
    174     /**
    175      * {@inheritDoc}
    176      *
    177      * <p>This implementation calls {@code entrySet().clear()}.
    178      */
    179     public void clear() {
    180         entrySet().clear();
    181     }
    182 
    183     /**
    184      * {@inheritDoc}
    185      *
    186      * <p>This implementation iterates its key set, looking for a key that
    187      * {@code key} equals.
    188      */
    189     public boolean containsKey(Object key) {
    190         Iterator<Map.Entry<K, V>> it = entrySet().iterator();
    191         if (key != null) {
    192             while (it.hasNext()) {
    193                 if (key.equals(it.next().getKey())) {
    194                     return true;
    195                 }
    196             }
    197         } else {
    198             while (it.hasNext()) {
    199                 if (it.next().getKey() == null) {
    200                     return true;
    201                 }
    202             }
    203         }
    204         return false;
    205     }
    206 
    207     /**
    208      * {@inheritDoc}
    209      *
    210      * <p>This implementation iterates its entry set, looking for an entry with
    211      * a value that {@code value} equals.
    212      */
    213     public boolean containsValue(Object value) {
    214         Iterator<Map.Entry<K, V>> it = entrySet().iterator();
    215         if (value != null) {
    216             while (it.hasNext()) {
    217                 if (value.equals(it.next().getValue())) {
    218                     return true;
    219                 }
    220             }
    221         } else {
    222             while (it.hasNext()) {
    223                 if (it.next().getValue() == null) {
    224                     return true;
    225                 }
    226             }
    227         }
    228         return false;
    229     }
    230 
    231     public abstract Set<Map.Entry<K, V>> entrySet();
    232 
    233     /**
    234      * {@inheritDoc}
    235      *
    236      * <p>This implementation first checks the structure of {@code object}. If
    237      * it is not a map or of a different size, this returns false. Otherwise it
    238      * iterates its own entry set, looking up each entry's key in {@code
    239      * object}. If any value does not equal the other map's value for the same
    240      * key, this returns false. Otherwise it returns true.
    241      */
    242     @Override public boolean equals(Object object) {
    243         if (this == object) {
    244             return true;
    245         }
    246         if (object instanceof Map) {
    247             Map<?, ?> map = (Map<?, ?>) object;
    248             if (size() != map.size()) {
    249                 return false;
    250             }
    251 
    252             try {
    253                 for (Entry<K, V> entry : entrySet()) {
    254                     K key = entry.getKey();
    255                     V mine = entry.getValue();
    256                     Object theirs = map.get(key);
    257                     if (mine == null) {
    258                         if (theirs != null || !map.containsKey(key)) {
    259                             return false;
    260                         }
    261                     } else if (!mine.equals(theirs)) {
    262                         return false;
    263                     }
    264                 }
    265             } catch (NullPointerException ignored) {
    266                 return false;
    267             } catch (ClassCastException ignored) {
    268                 return false;
    269             }
    270             return true;
    271         }
    272         return false;
    273     }
    274 
    275     /**
    276      * {@inheritDoc}
    277      *
    278      * <p>This implementation iterates its entry set, looking for an entry with
    279      * a key that {@code key} equals.
    280      */
    281     public V get(Object key) {
    282         Iterator<Map.Entry<K, V>> it = entrySet().iterator();
    283         if (key != null) {
    284             while (it.hasNext()) {
    285                 Map.Entry<K, V> entry = it.next();
    286                 if (key.equals(entry.getKey())) {
    287                     return entry.getValue();
    288                 }
    289             }
    290         } else {
    291             while (it.hasNext()) {
    292                 Map.Entry<K, V> entry = it.next();
    293                 if (entry.getKey() == null) {
    294                     return entry.getValue();
    295                 }
    296             }
    297         }
    298         return null;
    299     }
    300 
    301     /**
    302      * {@inheritDoc}
    303      *
    304      * <p>This implementation iterates its entry set, summing the hashcodes of
    305      * its entries.
    306      */
    307     @Override public int hashCode() {
    308         int result = 0;
    309         Iterator<Map.Entry<K, V>> it = entrySet().iterator();
    310         while (it.hasNext()) {
    311             result += it.next().hashCode();
    312         }
    313         return result;
    314     }
    315 
    316     /**
    317      * {@inheritDoc}
    318      *
    319      * <p>This implementation compares {@code size()} to 0.
    320      */
    321     public boolean isEmpty() {
    322         return size() == 0;
    323     }
    324 
    325     /**
    326      * {@inheritDoc}
    327      *
    328      * <p>This implementation returns a view that calls through this to map. Its
    329      * iterator transforms this map's entry set iterator to return keys.
    330      */
    331     public Set<K> keySet() {
    332         if (keySet == null) {
    333             keySet = new AbstractSet<K>() {
    334                 @Override public boolean contains(Object object) {
    335                     return containsKey(object);
    336                 }
    337 
    338                 @Override public int size() {
    339                     return AbstractMap.this.size();
    340                 }
    341 
    342                 @Override public Iterator<K> iterator() {
    343                     return new Iterator<K>() {
    344                         Iterator<Map.Entry<K, V>> setIterator = entrySet().iterator();
    345 
    346                         public boolean hasNext() {
    347                             return setIterator.hasNext();
    348                         }
    349 
    350                         public K next() {
    351                             return setIterator.next().getKey();
    352                         }
    353 
    354                         public void remove() {
    355                             setIterator.remove();
    356                         }
    357                     };
    358                 }
    359             };
    360         }
    361         return keySet;
    362     }
    363 
    364     /**
    365      * {@inheritDoc}
    366      *
    367      * <p>This base implementation throws {@code UnsupportedOperationException}.
    368      */
    369     public V put(K key, V value) {
    370         throw new UnsupportedOperationException();
    371     }
    372 
    373     /**
    374      * {@inheritDoc}
    375      *
    376      * <p>This implementation iterates through {@code map}'s entry set, calling
    377      * {@code put()} for each.
    378      */
    379     public void putAll(Map<? extends K, ? extends V> map) {
    380         for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
    381             put(entry.getKey(), entry.getValue());
    382         }
    383     }
    384 
    385     /**
    386      * {@inheritDoc}
    387      *
    388      * <p>This implementation iterates its entry set, removing the entry with
    389      * a key that {@code key} equals.
    390      */
    391     public V remove(Object key) {
    392         Iterator<Map.Entry<K, V>> it = entrySet().iterator();
    393         if (key != null) {
    394             while (it.hasNext()) {
    395                 Map.Entry<K, V> entry = it.next();
    396                 if (key.equals(entry.getKey())) {
    397                     it.remove();
    398                     return entry.getValue();
    399                 }
    400             }
    401         } else {
    402             while (it.hasNext()) {
    403                 Map.Entry<K, V> entry = it.next();
    404                 if (entry.getKey() == null) {
    405                     it.remove();
    406                     return entry.getValue();
    407                 }
    408             }
    409         }
    410         return null;
    411     }
    412 
    413     /**
    414      * {@inheritDoc}
    415      *
    416      * <p>This implementation returns its entry set's size.
    417      */
    418     public int size() {
    419         return entrySet().size();
    420     }
    421 
    422     /**
    423      * {@inheritDoc}
    424      *
    425      * <p>This implementation composes a string by iterating its entry set. If
    426      * this map contains itself as a key or a value, the string "(this Map)"
    427      * will appear in its place.
    428      */
    429     @Override public String toString() {
    430         if (isEmpty()) {
    431             return "{}";
    432         }
    433 
    434         StringBuilder buffer = new StringBuilder(size() * 28);
    435         buffer.append('{');
    436         Iterator<Map.Entry<K, V>> it = entrySet().iterator();
    437         while (it.hasNext()) {
    438             Map.Entry<K, V> entry = it.next();
    439             Object key = entry.getKey();
    440             if (key != this) {
    441                 buffer.append(key);
    442             } else {
    443                 buffer.append("(this Map)");
    444             }
    445             buffer.append('=');
    446             Object value = entry.getValue();
    447             if (value != this) {
    448                 buffer.append(value);
    449             } else {
    450                 buffer.append("(this Map)");
    451             }
    452             if (it.hasNext()) {
    453                 buffer.append(", ");
    454             }
    455         }
    456         buffer.append('}');
    457         return buffer.toString();
    458     }
    459 
    460     /**
    461      * {@inheritDoc}
    462      *
    463      * <p>This implementation returns a view that calls through this to map. Its
    464      * iterator transforms this map's entry set iterator to return values.
    465      */
    466     public Collection<V> values() {
    467         if (valuesCollection == null) {
    468             valuesCollection = new AbstractCollection<V>() {
    469                 @Override public int size() {
    470                     return AbstractMap.this.size();
    471                 }
    472 
    473                 @Override public boolean contains(Object object) {
    474                     return containsValue(object);
    475                 }
    476 
    477                 @Override public Iterator<V> iterator() {
    478                     return new Iterator<V>() {
    479                         Iterator<Map.Entry<K, V>> setIterator = entrySet().iterator();
    480 
    481                         public boolean hasNext() {
    482                             return setIterator.hasNext();
    483                         }
    484 
    485                         public V next() {
    486                             return setIterator.next().getValue();
    487                         }
    488 
    489                         public void remove() {
    490                             setIterator.remove();
    491                         }
    492                     };
    493                 }
    494             };
    495         }
    496         return valuesCollection;
    497     }
    498 
    499     @SuppressWarnings("unchecked")
    500     @Override protected Object clone() throws CloneNotSupportedException {
    501         AbstractMap<K, V> result = (AbstractMap<K, V>) super.clone();
    502         result.keySet = null;
    503         result.valuesCollection = null;
    504         return result;
    505     }
    506 }
    507