    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.collections4.bidimap;
    018
    019import java.util.Collection;
    020import java.util.Iterator;
    021import java.util.Map;
    022import java.util.Objects;
    023import java.util.Set;
    024import java.util.function.Predicate;
    025
    026import org.apache.commons.collections4.BidiMap;
    027import org.apache.commons.collections4.MapIterator;
    028import org.apache.commons.collections4.ResettableIterator;
    029import org.apache.commons.collections4.collection.AbstractCollectionDecorator;
    030import org.apache.commons.collections4.iterators.AbstractIteratorDecorator;
    031import org.apache.commons.collections4.keyvalue.AbstractMapEntryDecorator;
    032
    033/**
    034 * Abstract {@link BidiMap} implemented using two maps.
    035 * <p>
    036 * An implementation can be written simply by implementing the
    037 * {@link #createBidiMap(Map, Map, BidiMap)} method.
    038 * </p>
    039 *
    040 * @param <K> the type of the keys in the map
    041 * @param <V> the type of the values in the map
    042 *
    043 * @see DualHashBidiMap
    044 * @see DualTreeBidiMap
    045 * @since 3.0
    046 */
    047public abstract class AbstractDualBidiMap<K, V> implements BidiMap<K, V> {
    048
    049    /**
    050     * Inner class MapIterator.
    051     *
    052     * @param <K> the type of the keys.
    053     * @param <V> the type of the values.
    054     */
    055    protected static class BidiMapIterator<K, V> implements MapIterator<K, V>, ResettableIterator<K> {
    056
    057        /** The parent map */
    058        protected final AbstractDualBidiMap<K, V> parent;
    059
    060        /** The iterator being wrapped */
    061        protected Iterator<Map.Entry<K, V>> iterator;
    062
    063        /** The last returned entry */
    064        protected Map.Entry<K, V> last;
    065
    066        /** Whether remove is allowed at present */
    067        protected boolean canRemove;
    068
    069        /**
    070         * Constructs a new instance.
    071         * @param parent  the parent map
    072         */
    073        protected BidiMapIterator(final AbstractDualBidiMap<K, V> parent) {
    074            this.parent = parent;
    075            this.iterator = parent.normalMap.entrySet().iterator();
    076        }
    077
    078        @Override
    079        public K getKey() {
    080            if (last == null) {
    081                throw new IllegalStateException(
    082                        "Iterator getKey() can only be called after next() and before remove()");
    083            }
    084            return last.getKey();
    085        }
    086
    087        @Override
    088        public V getValue() {
    089            if (last == null) {
    090                throw new IllegalStateException(
    091                        "Iterator getValue() can only be called after next() and before remove()");
    092            }
    093            return last.getValue();
    094        }
    095
    096        @Override
    097        public boolean hasNext() {
    098            return iterator.hasNext();
    099        }
    100
    101        @Override
    102        public K next() {
    103            last = iterator.next();
    104            canRemove = true;
    105            return last.getKey();
    106        }
    107
    108        @Override
    109        public void remove() {
    110            if (!canRemove) {
    111                throw new IllegalStateException("Iterator remove() can only be called once after next()");
    112            }
    113            // store value as remove may change the entry in the decorator (e.g. TreeMap)
    114            final V value = last.getValue();
    115            iterator.remove();
    116            parent.reverseMap.remove(value);
    117            last = null;
    118            canRemove = false;
    119        }
    120
    121        @Override
    122        public void reset() {
    123            iterator = parent.normalMap.entrySet().iterator();
    124            last = null;
    125            canRemove = false;
    126        }
    127
    128        @Override
    129        public V setValue(final V value) {
    130            if (last == null) {
    131                throw new IllegalStateException(
    132                        "Iterator setValue() can only be called after next() and before remove()");
    133            }
    134            if (parent.reverseMap.containsKey(value) &&
    135                parent.reverseMap.get(value) != last.getKey()) {
    136                throw new IllegalArgumentException(
    137                        "Cannot use setValue() when the object being set is already in the map");
    138            }
    139            return parent.put(last.getKey(), value);
    140        }
    141
    142        @Override
    143        public String toString() {
    144            if (last != null) {
    145                return "MapIterator[" + getKey() + "=" + getValue() + "]";
    146            }
    147            return "MapIterator[]";
    148        }
    149    }
    150
    151    /**
    152     * Inner class EntrySet.
    153     *
    154     * @param <K> the type of the keys.
    155     * @param <V> the type of the values.
    156     */
    157    protected static class EntrySet<K, V> extends View<K, V, Map.Entry<K, V>> implements Set<Map.Entry<K, V>> {
    158
    159        /** Serialization version */
    160        private static final long serialVersionUID = 4040410962603292348L;
    161
    162        /**
    163         * Constructs a new instance.
    164         *
    165         * @param parent  the parent BidiMap
    166         */
    167        protected EntrySet(final AbstractDualBidiMap<K, V> parent) {
    168            super(parent.normalMap.entrySet(), parent);
    169        }
    170
    171        @Override
    172        public Iterator<Map.Entry<K, V>> iterator() {
    173            return parent.createEntrySetIterator(super.iterator());
    174        }
    175
    176        @Override
    177        public boolean remove(final Object obj) {
    178            if (!(obj instanceof Map.Entry)) {
    179                return false;
    180            }
    181            final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
    182            final Object key = entry.getKey();
    183            if (parent.containsKey(key)) {
    184                final V value = parent.normalMap.get(key);
    185                if (value == null ? entry.getValue() == null : value.equals(entry.getValue())) {
    186                    parent.normalMap.remove(key);
    187                    parent.reverseMap.remove(value);
    188                    return true;
    189                }
    190            }
    191            return false;
    192        }
    193    }
    194
    195    /**
    196     * Inner class EntrySetIterator.
    197     *
    198     * @param <K> the type of the keys.
    199     * @param <V> the type of the values.
    200     */
    201    protected static class EntrySetIterator<K, V> extends AbstractIteratorDecorator<Map.Entry<K, V>> {
    202
    203        /** The parent map */
    204        protected final AbstractDualBidiMap<K, V> parent;
    205
    206        /** The last returned entry */
    207        protected Map.Entry<K, V> last;
    208
    209        /** Whether remove is allowed at present */
    210        protected boolean canRemove;
    211
    212        /**
    213         * Constructs a new instance.
    214         * @param iterator  the iterator to decorate
    215         * @param parent  the parent map
    216         */
    217        protected EntrySetIterator(final Iterator<Map.Entry<K, V>> iterator, final AbstractDualBidiMap<K, V> parent) {
    218            super(iterator);
    219            this.parent = parent;
    220        }
    221
    222        @Override
    223        public Map.Entry<K, V> next() {
    224            last = new MapEntry<>(super.next(), parent);
    225            canRemove = true;
    226            return last;
    227        }
    228
    229        @Override
    230        public void remove() {
    231            if (!canRemove) {
    232                throw new IllegalStateException("Iterator remove() can only be called once after next()");
    233            }
    234            // store value as remove may change the entry in the decorator (e.g. TreeMap)
    235            final Object value = last.getValue();
    236            super.remove();
    237            parent.reverseMap.remove(value);
    238            last = null;
    239            canRemove = false;
    240        }
    241    }
    242
    243    /**
    244     * Inner class KeySet.
    245     *
    246     * @param <K> the type of elements maintained by this set
    247     */
    248    protected static class KeySet<K> extends View<K, Object, K> implements Set<K> {
    249
    250        /** Serialization version */
    251        private static final long serialVersionUID = -7107935777385040694L;
    252
    253        /**
    254         * Constructs a new instance.
    255         *
    256         * @param parent  the parent BidiMap
    257         */
    258        @SuppressWarnings("unchecked")
    259        protected KeySet(final AbstractDualBidiMap<K, ?> parent) {
    260            super(parent.normalMap.keySet(), (AbstractDualBidiMap<K, Object>) parent);
    261        }
    262
    263        @Override
    264        public boolean contains(final Object key) {
    265            return parent.normalMap.containsKey(key);
    266        }
    267
    268        @Override
    269        public Iterator<K> iterator() {
    270            return parent.createKeySetIterator(super.iterator());
    271        }
    272
    273        @Override
    274        public boolean remove(final Object key) {
    275            if (parent.normalMap.containsKey(key)) {
    276                final Object value = parent.normalMap.remove(key);
    277                parent.reverseMap.remove(value);
    278                return true;
    279            }
    280            return false;
    281        }
    282    }
    283
    284    /**
    285     * Inner class KeySetIterator.
    286     *
    287     * @param <K> the key type.
    288     */
    289    protected static class KeySetIterator<K> extends AbstractIteratorDecorator<K> {
    290
    291        /** The parent map */
    292        protected final AbstractDualBidiMap<K, ?> parent;
    293
    294        /** The last returned key */
    295        protected K lastKey;
    296
    297        /** Whether remove is allowed at present */
    298        protected boolean canRemove;
    299
    300        /**
    301         * Constructs a new instance.
    302         * @param iterator  the iterator to decorate
    303         * @param parent  the parent map
    304         */
    305        protected KeySetIterator(final Iterator<K> iterator, final AbstractDualBidiMap<K, ?> parent) {
    306            super(iterator);
    307            this.parent = parent;
    308        }
    309
    310        @Override
    311        public K next() {
    312            lastKey = super.next();
    313            canRemove = true;
    314            return lastKey;
    315        }
    316
    317        @Override
    318        public void remove() {
    319            if (!canRemove) {
    320                throw new IllegalStateException("Iterator remove() can only be called once after next()");
    321            }
    322            final Object value = parent.normalMap.get(lastKey);
    323            super.remove();
    324            parent.reverseMap.remove(value);
    325            lastKey = null;
    326            canRemove = false;
    327        }
    328    }
    329
    330    /**
    331     * Inner class MapEntry.
    332     *
    333     * @param <K> the type of the keys.
    334     * @param <V> the type of the values.
    335     */
    336    protected static class MapEntry<K, V> extends AbstractMapEntryDecorator<K, V> {
    337
    338        /** The parent map */
    339        protected final AbstractDualBidiMap<K, V> parent;
    340
    341        /**
    342         * Constructs a new instance.
    343         * @param entry  the entry to decorate
    344         * @param parent  the parent map
    345         */
    346        protected MapEntry(final Map.Entry<K, V> entry, final AbstractDualBidiMap<K, V> parent) {
    347            super(entry);
    348            this.parent = parent;
    349        }
    350
    351        @Override
    352        public V setValue(final V value) {
    353            final K key = getKey();
    354            if (parent.reverseMap.containsKey(value) &&
    355                parent.reverseMap.get(value) != key) {
    356                throw new IllegalArgumentException(
    357                        "Cannot use setValue() when the object being set is already in the map");
    358            }
    359            parent.put(key, value);
    360            return super.setValue(value);
    361        }
    362    }
    363
    364    /**
    365     * Inner class Values.
    366     *
    367     * @param <V> the type of the values.
    368     */
    369    protected static class Values<V> extends View<Object, V, V> implements Set<V> {
    370
    371        /** Serialization version */
    372        private static final long serialVersionUID = 4023777119829639864L;
    373
    374        /**
    375         * Constructs a new instance.
    376         *
    377         * @param parent  the parent BidiMap
    378         */
    379        @SuppressWarnings("unchecked")
    380        protected Values(final AbstractDualBidiMap<?, V> parent) {
    381            super(parent.normalMap.values(), (AbstractDualBidiMap<Object, V>) parent);
    382        }
    383
    384        @Override
    385        public boolean contains(final Object value) {
    386            return parent.reverseMap.containsKey(value);
    387        }
    388
    389        @Override
    390        public Iterator<V> iterator() {
    391            return parent.createValuesIterator(super.iterator());
    392        }
    393
    394        @Override
    395        public boolean remove(final Object value) {
    396            if (parent.reverseMap.containsKey(value)) {
    397                final Object key = parent.reverseMap.remove(value);
    398                parent.normalMap.remove(key);
    399                return true;
    400            }
    401            return false;
    402        }
    403    }
    404
    405    /**
    406     * Inner class ValuesIterator.
    407     *
    408     * @param <V> the value type.
    409     */
    410    protected static class ValuesIterator<V> extends AbstractIteratorDecorator<V> {
    411
    412        /** The parent map */
    413        protected final AbstractDualBidiMap<Object, V> parent;
    414
    415        /** The last returned value */
    416        protected V lastValue;
    417
    418        /** Whether remove is allowed at present */
    419        protected boolean canRemove;
    420
    421        /**
    422         * Constructs a new instance.
    423         * @param iterator  the iterator to decorate
    424         * @param parent  the parent map
    425         */
    426        @SuppressWarnings("unchecked")
    427        protected ValuesIterator(final Iterator<V> iterator, final AbstractDualBidiMap<?, V> parent) {
    428            super(iterator);
    429            this.parent = (AbstractDualBidiMap<Object, V>) parent;
    430        }
    431
    432        @Override
    433        public V next() {
    434            lastValue = super.next();
    435            canRemove = true;
    436            return lastValue;
    437        }
    438
    439        @Override
    440        public void remove() {
    441            if (!canRemove) {
    442                throw new IllegalStateException("Iterator remove() can only be called once after next()");
    443            }
    444            super.remove(); // removes from maps[0]
    445            parent.reverseMap.remove(lastValue);
    446            lastValue = null;
    447            canRemove = false;
    448        }
    449    }
    450
    451    /**
    452     * Inner class View.
    453     *
    454     * @param <K> the type of the keys in the map.
    455     * @param <V> the type of the values in the map.
    456     * @param <E> the type of the elements in the collection.
    457     */
    458    protected abstract static class View<K, V, E> extends AbstractCollectionDecorator<E> {
    459
    460        /** Generated serial version ID. */
    461        private static final long serialVersionUID = 4621510560119690639L;
    462
    463        /** The parent map */
    464        protected final AbstractDualBidiMap<K, V> parent;
    465
    466        /**
    467         * Constructs a new instance.
    468         *
    469         * @param coll  the collection view being decorated
    470         * @param parent  the parent BidiMap
    471         */
    472        protected View(final Collection<E> coll, final AbstractDualBidiMap<K, V> parent) {
    473            super(coll);
    474            this.parent = parent;
    475        }
    476
    477        @Override
    478        public void clear() {
    479            parent.clear();
    480        }
    481
    482        @Override
    483        public boolean equals(final Object object) {
    484            return object == this || decorated().equals(object);
    485        }
    486
    487        @Override
    488        public int hashCode() {
    489            return decorated().hashCode();
    490        }
    491
    492        @Override
    493        public boolean removeAll(final Collection<?> coll) {
    494            if (parent.isEmpty() || coll.isEmpty()) {
    495                return false;
    496            }
    497            boolean modified = false;
    498            for (final Object current : coll) {
    499                modified |= remove(current);
    500            }
    501            return modified;
    502        }
    503
    504        /**
    505         * @since 4.4
    506         */
    507        @Override
    508        public boolean removeIf(final Predicate<? super E> filter) {
    509            if (parent.isEmpty() || Objects.isNull(filter)) {
    510                return false;
    511            }
    512            boolean modified = false;
    513            final Iterator<?> it = iterator();
    514            while (it.hasNext()) {
    515                @SuppressWarnings("unchecked")
    516                final E e = (E) it.next();
    517                if (filter.test(e)) {
    518                    it.remove();
    519                    modified = true;
    520                }
    521            }
    522            return modified;
    523        }
    524
    525        /**
    526         * {@inheritDoc}
    527         * <p>
    528         * This implementation iterates over the elements of this bidi map, checking each element in
    529         * turn to see if it's contained in {@code coll}. If it's not contained, it's removed
    530         * from this bidi map. As a consequence, it is advised to use a collection type for
    531         * {@code coll} that provides a fast (e.g. O(1)) implementation of
    532         * {@link Collection#contains(Object)}.
    533         */
    534        @Override
    535        public boolean retainAll(final Collection<?> coll) {
    536            if (parent.isEmpty()) {
    537                return false;
    538            }
    539            if (coll.isEmpty()) {
    540                parent.clear();
    541                return true;
    542            }
    543            boolean modified = false;
    544            final Iterator<E> it = iterator();
    545            while (it.hasNext()) {
    546                if (!coll.contains(it.next())) {
    547                    it.remove();
    548                    modified = true;
    549                }
    550            }
    551            return modified;
    552        }
    553    }
    554
    555    /**
    556     * Normal delegate map.
    557     */
    558    transient Map<K, V> normalMap;
    559
    560    // Map delegation
    561
    562    /**
    563     * Reverse delegate map.
    564     */
    565    transient Map<V, K> reverseMap;
    566
    567    /**
    568     * Inverse view of this map.
    569     */
    570    transient BidiMap<V, K> inverseBidiMap;
    571
    572    /**
    573     * View of the keys.
    574     */
    575    transient Set<K> keySet;
    576
    577    /**
    578     * View of the values.
    579     */
    580    transient Set<V> values;
    581
    582    /**
    583     * View of the entries.
    584     */
    585    transient Set<Map.Entry<K, V>> entrySet;
    586
    587    /**
    588     * Creates an empty map, initialized by {@code createMap}.
    589     * <p>
    590     * This constructor remains in place for deserialization.
    591     * All other usage is deprecated in favour of
    592     * {@link #AbstractDualBidiMap(Map, Map)}.
    593     */
    594    protected AbstractDualBidiMap() {
    595    }
    596
    597    /**
    598     * Creates an empty map using the two maps specified as storage.
    599     * <p>
    600     * The two maps must be a matching pair, normal and reverse.
    601     * They will typically both be empty.
    602     * <p>
    603     * Neither map is validated, so nulls may be passed in.
    604     * If you choose to do this then the subclass constructor must populate
    605     * the {@code maps[]} instance variable itself.
    606     *
    607     * @param normalMap  the normal direction map
    608     * @param reverseMap  the reverse direction map
    609     * @since 3.1
    610     */
    611    protected AbstractDualBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap) {
    612        this.normalMap = normalMap;
    613        this.reverseMap = reverseMap;
    614    }
    615
    616    // BidiMap changes
    617
    618    /**
    619     * Constructs a map that decorates the specified maps,
    620     * used by the subclass {@code createBidiMap} implementation.
    621     *
    622     * @param normalMap  the normal direction map
    623     * @param reverseMap  the reverse direction map
    624     * @param inverseBidiMap  the inverse BidiMap
    625     */
    626    protected AbstractDualBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap,
    627                                  final BidiMap<V, K> inverseBidiMap) {
    628        this.normalMap = normalMap;
    629        this.reverseMap = reverseMap;
    630        this.inverseBidiMap = inverseBidiMap;
    631    }
    632
    633    @Override
    634    public void clear() {
    635        normalMap.clear();
    636        reverseMap.clear();
    637    }
    638
    639    @Override
    640    public boolean containsKey(final Object key) {
    641        return normalMap.containsKey(key);
    642    }
    643
    644    @Override
    645    public boolean containsValue(final Object value) {
    646        return reverseMap.containsKey(value);
    647    }
    648
    649    /**
    650     * Creates a new instance of the subclass.
    651     *
    652     * @param normalMap  the normal direction map
    653     * @param reverseMap  the reverse direction map
    654     * @param inverseMap  this map, which is the inverse in the new map
    655     * @return the bidi map
    656     */
    657    protected abstract BidiMap<V, K> createBidiMap(Map<V, K> normalMap, Map<K, V> reverseMap, BidiMap<K, V> inverseMap);
    658
    659    /**
    660     * Creates an entry set iterator.
    661     * Subclasses can override this to return iterators with different properties.
    662     *
    663     * @param iterator  the iterator to decorate
    664     * @return the entrySet iterator
    665     */
    666    protected Iterator<Map.Entry<K, V>> createEntrySetIterator(final Iterator<Map.Entry<K, V>> iterator) {
    667        return new EntrySetIterator<>(iterator, this);
    668    }
    669
    670    /**
    671     * Creates a key set iterator.
    672     * Subclasses can override this to return iterators with different properties.
    673     *
    674     * @param iterator  the iterator to decorate
    675     * @return the keySet iterator
    676     */
    677    protected Iterator<K> createKeySetIterator(final Iterator<K> iterator) {
    678        return new KeySetIterator<>(iterator, this);
    679    }
    680
    681    /**
    682     * Creates a values iterator.
    683     * Subclasses can override this to return iterators with different properties.
    684     *
    685     * @param iterator  the iterator to decorate
    686     * @return the values iterator
    687     */
    688    protected Iterator<V> createValuesIterator(final Iterator<V> iterator) {
    689        return new ValuesIterator<>(iterator, this);
    690    }
    691
    692    /**
    693     * Gets an entrySet view of the map.
    694     * Changes made on the set are reflected in the map.
    695     * The set supports remove and clear but not add.
    696     * <p>
    697     * The Map Entry setValue() method only allow a new value to be set.
    698     * If the value being set is already in the map, an IllegalArgumentException
    699     * is thrown (as setValue cannot change the size of the map).
    700     *
    701     * @return the entrySet view
    702     */
    703    @Override
    704    public Set<Map.Entry<K, V>> entrySet() {
    705        if (entrySet == null) {
    706            entrySet = new EntrySet<>(this);
    707        }
    708        return entrySet;
    709    }
    710
    711    @Override
    712    public boolean equals(final Object obj) {
    713        return normalMap.equals(obj);
    714    }
    715
    716    @Override
    717    public V get(final Object key) {
    718        return normalMap.get(key);
    719    }
    720
    721    @Override
    722    public K getKey(final Object value) {
    723        return reverseMap.get(value);
    724    }
    725
    726    @Override
    727    public int hashCode() {
    728        return normalMap.hashCode();
    729    }
    730
    731    @Override
    732    public BidiMap<V, K> inverseBidiMap() {
    733        if (inverseBidiMap == null) {
    734            inverseBidiMap = createBidiMap(reverseMap, normalMap, this);
    735        }
    736        return inverseBidiMap;
    737    }
    738
    739    @Override
    740    public boolean isEmpty() {
    741        return normalMap.isEmpty();
    742    }
    743
    744    // Map views
    745    /**
    746     * Gets a keySet view of the map.
    747     * Changes made on the view are reflected in the map.
    748     * The set supports remove and clear but not add.
    749     *
    750     * @return the keySet view
    751     */
    752    @Override
    753    public Set<K> keySet() {
    754        if (keySet == null) {
    755            keySet = new KeySet<>(this);
    756        }
    757        return keySet;
    758    }
    759
    760    // BidiMap
    761    /**
    762     * Obtains a {@code MapIterator} over the map.
    763     * The iterator implements {@link BidiMapIterator}.
    764     * This implementation relies on the entrySet iterator.
    765     * <p>
    766     *
    767     * @return a map iterator
    768     */
    769    @Override
    770    public MapIterator<K, V> mapIterator() {
    771        return new BidiMapIterator<>(this);
    772    }
    773
    774    @Override
    775    public V put(final K key, final V value) {
    776        if (normalMap.containsKey(key)) {
    777            reverseMap.remove(normalMap.get(key));
    778        }
    779        if (reverseMap.containsKey(value)) {
    780            normalMap.remove(reverseMap.get(value));
    781        }
    782        final V obj = normalMap.put(key, value);
    783        reverseMap.put(value, key);
    784        return obj;
    785    }
    786
    787    @Override
    788    public void putAll(final Map<? extends K, ? extends V> map) {
    789        for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
    790            put(entry.getKey(), entry.getValue());
    791        }
    792    }
    793
    794    @Override
    795    public V remove(final Object key) {
    796        V value = null;
    797        if (normalMap.containsKey(key)) {
    798            value = normalMap.remove(key);
    799            reverseMap.remove(value);
    800        }
    801        return value;
    802    }
    803
    804    @Override
    805    public K removeValue(final Object value) {
    806        K key = null;
    807        if (reverseMap.containsKey(value)) {
    808            key = reverseMap.remove(value);
    809            normalMap.remove(key);
    810        }
    811        return key;
    812    }
    813
    814    @Override
    815    public int size() {
    816        return normalMap.size();
    817    }
    818
    819    @Override
    820    public String toString() {
    821        return normalMap.toString();
    822    }
    823
    824    /**
    825     * Gets a values view of the map.
    826     * Changes made on the view are reflected in the map.
    827     * The set supports remove and clear but not add.
    828     *
    829     * @return the values view
    830     */
    831    @Override
    832    public Set<V> values() {
    833        if (values == null) {
    834            values = new Values<>(this);
    835        }
    836        return values;
    837    }
    838
    839}