AbstractDualBidiMap.java

  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. package org.apache.commons.collections4.bidimap;

  18. import java.util.Collection;
  19. import java.util.Iterator;
  20. import java.util.Map;
  21. import java.util.Objects;
  22. import java.util.Set;
  23. import java.util.function.Predicate;

  24. import org.apache.commons.collections4.BidiMap;
  25. import org.apache.commons.collections4.MapIterator;
  26. import org.apache.commons.collections4.ResettableIterator;
  27. import org.apache.commons.collections4.collection.AbstractCollectionDecorator;
  28. import org.apache.commons.collections4.iterators.AbstractIteratorDecorator;
  29. import org.apache.commons.collections4.keyvalue.AbstractMapEntryDecorator;

  30. /**
  31.  * Abstract {@link BidiMap} implemented using two maps.
  32.  * <p>
  33.  * An implementation can be written simply by implementing the
  34.  * {@link #createBidiMap(Map, Map, BidiMap)} method.
  35.  * </p>
  36.  *
  37.  * @param <K> the type of the keys in the map
  38.  * @param <V> the type of the values in the map
  39.  * @see DualHashBidiMap
  40.  * @see DualTreeBidiMap
  41.  * @since 3.0
  42.  */
  43. public abstract class AbstractDualBidiMap<K, V> implements BidiMap<K, V> {

  44.     /**
  45.      * Inner class MapIterator.
  46.      *
  47.      * @param <K> the type of the keys.
  48.      * @param <V> the type of the values.
  49.      */
  50.     protected static class BidiMapIterator<K, V> implements MapIterator<K, V>, ResettableIterator<K> {

  51.         /** The parent map */
  52.         protected final AbstractDualBidiMap<K, V> parent;

  53.         /** The iterator being wrapped */
  54.         protected Iterator<Map.Entry<K, V>> iterator;

  55.         /** The last returned entry */
  56.         protected Map.Entry<K, V> last;

  57.         /** Whether remove is allowed at present */
  58.         protected boolean canRemove;

  59.         /**
  60.          * Constructs a new instance.
  61.          * @param parent  the parent map
  62.          */
  63.         protected BidiMapIterator(final AbstractDualBidiMap<K, V> parent) {
  64.             this.parent = parent;
  65.             this.iterator = parent.normalMap.entrySet().iterator();
  66.         }

  67.         @Override
  68.         public K getKey() {
  69.             if (last == null) {
  70.                 throw new IllegalStateException(
  71.                         "Iterator getKey() can only be called after next() and before remove()");
  72.             }
  73.             return last.getKey();
  74.         }

  75.         @Override
  76.         public V getValue() {
  77.             if (last == null) {
  78.                 throw new IllegalStateException(
  79.                         "Iterator getValue() can only be called after next() and before remove()");
  80.             }
  81.             return last.getValue();
  82.         }

  83.         @Override
  84.         public boolean hasNext() {
  85.             return iterator.hasNext();
  86.         }

  87.         @Override
  88.         public K next() {
  89.             last = iterator.next();
  90.             canRemove = true;
  91.             return last.getKey();
  92.         }

  93.         @Override
  94.         public void remove() {
  95.             if (!canRemove) {
  96.                 throw new IllegalStateException("Iterator remove() can only be called once after next()");
  97.             }
  98.             // store value as remove may change the entry in the decorator (for example TreeMap)
  99.             final V value = last.getValue();
  100.             iterator.remove();
  101.             parent.reverseMap.remove(value);
  102.             last = null;
  103.             canRemove = false;
  104.         }

  105.         @Override
  106.         public void reset() {
  107.             iterator = parent.normalMap.entrySet().iterator();
  108.             last = null;
  109.             canRemove = false;
  110.         }

  111.         @Override
  112.         public V setValue(final V value) {
  113.             if (last == null) {
  114.                 throw new IllegalStateException(
  115.                         "Iterator setValue() can only be called after next() and before remove()");
  116.             }
  117.             if (parent.reverseMap.containsKey(value) &&
  118.                 parent.reverseMap.get(value) != last.getKey()) {
  119.                 throw new IllegalArgumentException(
  120.                         "Cannot use setValue() when the object being set is already in the map");
  121.             }
  122.             return parent.put(last.getKey(), value);
  123.         }

  124.         @Override
  125.         public String toString() {
  126.             if (last != null) {
  127.                 return "MapIterator[" + getKey() + "=" + getValue() + "]";
  128.             }
  129.             return "MapIterator[]";
  130.         }
  131.     }

  132.     /**
  133.      * Inner class EntrySet.
  134.      *
  135.      * @param <K> the type of the keys.
  136.      * @param <V> the type of the values.
  137.      */
  138.     protected static class EntrySet<K, V> extends View<K, V, Map.Entry<K, V>> implements Set<Map.Entry<K, V>> {

  139.         /** Serialization version */
  140.         private static final long serialVersionUID = 4040410962603292348L;

  141.         /**
  142.          * Constructs a new instance.
  143.          *
  144.          * @param parent  the parent BidiMap
  145.          */
  146.         protected EntrySet(final AbstractDualBidiMap<K, V> parent) {
  147.             super(parent.normalMap.entrySet(), parent);
  148.         }

  149.         @Override
  150.         public Iterator<Map.Entry<K, V>> iterator() {
  151.             return parent.createEntrySetIterator(super.iterator());
  152.         }

  153.         @Override
  154.         public boolean remove(final Object obj) {
  155.             if (!(obj instanceof Map.Entry)) {
  156.                 return false;
  157.             }
  158.             final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj;
  159.             final Object key = entry.getKey();
  160.             if (parent.containsKey(key)) {
  161.                 final V value = parent.normalMap.get(key);
  162.                 if (Objects.equals(value, entry.getValue())) {
  163.                     parent.normalMap.remove(key);
  164.                     parent.reverseMap.remove(value);
  165.                     return true;
  166.                 }
  167.             }
  168.             return false;
  169.         }
  170.     }

  171.     /**
  172.      * Inner class EntrySetIterator.
  173.      *
  174.      * @param <K> the type of the keys.
  175.      * @param <V> the type of the values.
  176.      */
  177.     protected static class EntrySetIterator<K, V> extends AbstractIteratorDecorator<Map.Entry<K, V>> {

  178.         /** The parent map */
  179.         protected final AbstractDualBidiMap<K, V> parent;

  180.         /** The last returned entry */
  181.         protected Map.Entry<K, V> last;

  182.         /** Whether remove is allowed at present */
  183.         protected boolean canRemove;

  184.         /**
  185.          * Constructs a new instance.
  186.          * @param iterator  the iterator to decorate
  187.          * @param parent  the parent map
  188.          */
  189.         protected EntrySetIterator(final Iterator<Map.Entry<K, V>> iterator, final AbstractDualBidiMap<K, V> parent) {
  190.             super(iterator);
  191.             this.parent = parent;
  192.         }

  193.         @Override
  194.         public Map.Entry<K, V> next() {
  195.             last = new MapEntry<>(super.next(), parent);
  196.             canRemove = true;
  197.             return last;
  198.         }

  199.         @Override
  200.         public void remove() {
  201.             if (!canRemove) {
  202.                 throw new IllegalStateException("Iterator remove() can only be called once after next()");
  203.             }
  204.             // store value as remove may change the entry in the decorator (for example TreeMap)
  205.             final Object value = last.getValue();
  206.             super.remove();
  207.             parent.reverseMap.remove(value);
  208.             last = null;
  209.             canRemove = false;
  210.         }
  211.     }

  212.     /**
  213.      * Inner class KeySet.
  214.      *
  215.      * @param <K> the type of elements maintained by this set
  216.      */
  217.     protected static class KeySet<K> extends View<K, Object, K> implements Set<K> {

  218.         /** Serialization version */
  219.         private static final long serialVersionUID = -7107935777385040694L;

  220.         /**
  221.          * Constructs a new instance.
  222.          *
  223.          * @param parent  the parent BidiMap
  224.          */
  225.         @SuppressWarnings("unchecked")
  226.         protected KeySet(final AbstractDualBidiMap<K, ?> parent) {
  227.             super(parent.normalMap.keySet(), (AbstractDualBidiMap<K, Object>) parent);
  228.         }

  229.         @Override
  230.         public boolean contains(final Object key) {
  231.             return parent.normalMap.containsKey(key);
  232.         }

  233.         @Override
  234.         public Iterator<K> iterator() {
  235.             return parent.createKeySetIterator(super.iterator());
  236.         }

  237.         @Override
  238.         public boolean remove(final Object key) {
  239.             if (parent.normalMap.containsKey(key)) {
  240.                 final Object value = parent.normalMap.remove(key);
  241.                 parent.reverseMap.remove(value);
  242.                 return true;
  243.             }
  244.             return false;
  245.         }
  246.     }

  247.     /**
  248.      * Inner class KeySetIterator.
  249.      *
  250.      * @param <K> the key type.
  251.      */
  252.     protected static class KeySetIterator<K> extends AbstractIteratorDecorator<K> {

  253.         /** The parent map */
  254.         protected final AbstractDualBidiMap<K, ?> parent;

  255.         /** The last returned key */
  256.         protected K lastKey;

  257.         /** Whether remove is allowed at present */
  258.         protected boolean canRemove;

  259.         /**
  260.          * Constructs a new instance.
  261.          * @param iterator  the iterator to decorate
  262.          * @param parent  the parent map
  263.          */
  264.         protected KeySetIterator(final Iterator<K> iterator, final AbstractDualBidiMap<K, ?> parent) {
  265.             super(iterator);
  266.             this.parent = parent;
  267.         }

  268.         @Override
  269.         public K next() {
  270.             lastKey = super.next();
  271.             canRemove = true;
  272.             return lastKey;
  273.         }

  274.         @Override
  275.         public void remove() {
  276.             if (!canRemove) {
  277.                 throw new IllegalStateException("Iterator remove() can only be called once after next()");
  278.             }
  279.             final Object value = parent.normalMap.get(lastKey);
  280.             super.remove();
  281.             parent.reverseMap.remove(value);
  282.             lastKey = null;
  283.             canRemove = false;
  284.         }
  285.     }

  286.     /**
  287.      * Inner class MapEntry.
  288.      *
  289.      * @param <K> the type of the keys.
  290.      * @param <V> the type of the values.
  291.      */
  292.     protected static class MapEntry<K, V> extends AbstractMapEntryDecorator<K, V> {

  293.         /** The parent map */
  294.         protected final AbstractDualBidiMap<K, V> parent;

  295.         /**
  296.          * Constructs a new instance.
  297.          * @param entry  the entry to decorate
  298.          * @param parent  the parent map
  299.          */
  300.         protected MapEntry(final Map.Entry<K, V> entry, final AbstractDualBidiMap<K, V> parent) {
  301.             super(entry);
  302.             this.parent = parent;
  303.         }

  304.         @Override
  305.         public V setValue(final V value) {
  306.             final K key = getKey();
  307.             if (parent.reverseMap.containsKey(value) &&
  308.                 parent.reverseMap.get(value) != key) {
  309.                 throw new IllegalArgumentException(
  310.                         "Cannot use setValue() when the object being set is already in the map");
  311.             }
  312.             parent.put(key, value);
  313.             return super.setValue(value);
  314.         }
  315.     }

  316.     /**
  317.      * Inner class Values.
  318.      *
  319.      * @param <V> the type of the values.
  320.      */
  321.     protected static class Values<V> extends View<Object, V, V> implements Set<V> {

  322.         /** Serialization version */
  323.         private static final long serialVersionUID = 4023777119829639864L;

  324.         /**
  325.          * Constructs a new instance.
  326.          *
  327.          * @param parent  the parent BidiMap
  328.          */
  329.         @SuppressWarnings("unchecked")
  330.         protected Values(final AbstractDualBidiMap<?, V> parent) {
  331.             super(parent.normalMap.values(), (AbstractDualBidiMap<Object, V>) parent);
  332.         }

  333.         @Override
  334.         public boolean contains(final Object value) {
  335.             return parent.reverseMap.containsKey(value);
  336.         }

  337.         @Override
  338.         public Iterator<V> iterator() {
  339.             return parent.createValuesIterator(super.iterator());
  340.         }

  341.         @Override
  342.         public boolean remove(final Object value) {
  343.             if (parent.reverseMap.containsKey(value)) {
  344.                 final Object key = parent.reverseMap.remove(value);
  345.                 parent.normalMap.remove(key);
  346.                 return true;
  347.             }
  348.             return false;
  349.         }
  350.     }

  351.     /**
  352.      * Inner class ValuesIterator.
  353.      *
  354.      * @param <V> the value type.
  355.      */
  356.     protected static class ValuesIterator<V> extends AbstractIteratorDecorator<V> {

  357.         /** The parent map */
  358.         protected final AbstractDualBidiMap<Object, V> parent;

  359.         /** The last returned value */
  360.         protected V lastValue;

  361.         /** Whether remove is allowed at present */
  362.         protected boolean canRemove;

  363.         /**
  364.          * Constructs a new instance.
  365.          * @param iterator  the iterator to decorate
  366.          * @param parent  the parent map
  367.          */
  368.         @SuppressWarnings("unchecked")
  369.         protected ValuesIterator(final Iterator<V> iterator, final AbstractDualBidiMap<?, V> parent) {
  370.             super(iterator);
  371.             this.parent = (AbstractDualBidiMap<Object, V>) parent;
  372.         }

  373.         @Override
  374.         public V next() {
  375.             lastValue = super.next();
  376.             canRemove = true;
  377.             return lastValue;
  378.         }

  379.         @Override
  380.         public void remove() {
  381.             if (!canRemove) {
  382.                 throw new IllegalStateException("Iterator remove() can only be called once after next()");
  383.             }
  384.             super.remove(); // removes from maps[0]
  385.             parent.reverseMap.remove(lastValue);
  386.             lastValue = null;
  387.             canRemove = false;
  388.         }
  389.     }

  390.     /**
  391.      * Inner class View.
  392.      *
  393.      * @param <K> the type of the keys in the map.
  394.      * @param <V> the type of the values in the map.
  395.      * @param <E> the type of the elements in the collection.
  396.      */
  397.     protected abstract static class View<K, V, E> extends AbstractCollectionDecorator<E> {

  398.         /** Generated serial version ID. */
  399.         private static final long serialVersionUID = 4621510560119690639L;

  400.         /** The parent map */
  401.         protected final AbstractDualBidiMap<K, V> parent;

  402.         /**
  403.          * Constructs a new instance.
  404.          *
  405.          * @param coll  the collection view being decorated
  406.          * @param parent  the parent BidiMap
  407.          */
  408.         protected View(final Collection<E> coll, final AbstractDualBidiMap<K, V> parent) {
  409.             super(coll);
  410.             this.parent = parent;
  411.         }

  412.         @Override
  413.         public void clear() {
  414.             parent.clear();
  415.         }

  416.         @Override
  417.         public boolean equals(final Object object) {
  418.             return object == this || decorated().equals(object);
  419.         }

  420.         @Override
  421.         public int hashCode() {
  422.             return decorated().hashCode();
  423.         }

  424.         @Override
  425.         public boolean removeAll(final Collection<?> coll) {
  426.             if (parent.isEmpty() || coll.isEmpty()) {
  427.                 return false;
  428.             }
  429.             boolean modified = false;
  430.             for (final Object current : coll) {
  431.                 modified |= remove(current);
  432.             }
  433.             return modified;
  434.         }

  435.         /**
  436.          * @since 4.4
  437.          */
  438.         @Override
  439.         public boolean removeIf(final Predicate<? super E> filter) {
  440.             if (parent.isEmpty() || Objects.isNull(filter)) {
  441.                 return false;
  442.             }
  443.             boolean modified = false;
  444.             final Iterator<?> it = iterator();
  445.             while (it.hasNext()) {
  446.                 @SuppressWarnings("unchecked")
  447.                 final E e = (E) it.next();
  448.                 if (filter.test(e)) {
  449.                     it.remove();
  450.                     modified = true;
  451.                 }
  452.             }
  453.             return modified;
  454.         }

  455.         /**
  456.          * {@inheritDoc}
  457.          * <p>
  458.          * This implementation iterates over the elements of this bidi map, checking each element in
  459.          * turn to see if it's contained in {@code coll}. If it's not contained, it's removed
  460.          * from this bidi map. As a consequence, it is advised to use a collection type for
  461.          * {@code coll} that provides a fast (for example O(1)) implementation of
  462.          * {@link Collection#contains(Object)}.
  463.          */
  464.         @Override
  465.         public boolean retainAll(final Collection<?> coll) {
  466.             if (parent.isEmpty()) {
  467.                 return false;
  468.             }
  469.             if (coll.isEmpty()) {
  470.                 parent.clear();
  471.                 return true;
  472.             }
  473.             boolean modified = false;
  474.             final Iterator<E> it = iterator();
  475.             while (it.hasNext()) {
  476.                 if (!coll.contains(it.next())) {
  477.                     it.remove();
  478.                     modified = true;
  479.                 }
  480.             }
  481.             return modified;
  482.         }
  483.     }

  484.     /**
  485.      * Normal delegate map.
  486.      */
  487.     transient Map<K, V> normalMap;

  488.     // Map delegation

  489.     /**
  490.      * Reverse delegate map.
  491.      */
  492.     transient Map<V, K> reverseMap;

  493.     /**
  494.      * Inverse view of this map.
  495.      */
  496.     transient BidiMap<V, K> inverseBidiMap;

  497.     /**
  498.      * View of the keys.
  499.      */
  500.     transient Set<K> keySet;

  501.     /**
  502.      * View of the values.
  503.      */
  504.     transient Set<V> values;

  505.     /**
  506.      * View of the entries.
  507.      */
  508.     transient Set<Map.Entry<K, V>> entrySet;

  509.     /**
  510.      * Creates an empty map, initialized by {@code createMap}.
  511.      * <p>
  512.      * This constructor remains in place for deserialization.
  513.      * All other usage is deprecated in favor of
  514.      * {@link #AbstractDualBidiMap(Map, Map)}.
  515.      */
  516.     protected AbstractDualBidiMap() {
  517.     }

  518.     /**
  519.      * Creates an empty map using the two maps specified as storage.
  520.      * <p>
  521.      * The two maps must be a matching pair, normal and reverse.
  522.      * They will typically both be empty.
  523.      * <p>
  524.      * Neither map is validated, so nulls may be passed in.
  525.      * If you choose to do this then the subclass constructor must populate
  526.      * the {@code maps[]} instance variable itself.
  527.      *
  528.      * @param normalMap  the normal direction map
  529.      * @param reverseMap  the reverse direction map
  530.      * @since 3.1
  531.      */
  532.     protected AbstractDualBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap) {
  533.         this.normalMap = normalMap;
  534.         this.reverseMap = reverseMap;
  535.     }

  536.     // BidiMap changes

  537.     /**
  538.      * Constructs a map that decorates the specified maps,
  539.      * used by the subclass {@code createBidiMap} implementation.
  540.      *
  541.      * @param normalMap  the normal direction map
  542.      * @param reverseMap  the reverse direction map
  543.      * @param inverseBidiMap  the inverse BidiMap
  544.      */
  545.     protected AbstractDualBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap,
  546.                                   final BidiMap<V, K> inverseBidiMap) {
  547.         this.normalMap = normalMap;
  548.         this.reverseMap = reverseMap;
  549.         this.inverseBidiMap = inverseBidiMap;
  550.     }

  551.     @Override
  552.     public void clear() {
  553.         normalMap.clear();
  554.         reverseMap.clear();
  555.     }

  556.     @Override
  557.     public boolean containsKey(final Object key) {
  558.         return normalMap.containsKey(key);
  559.     }

  560.     @Override
  561.     public boolean containsValue(final Object value) {
  562.         return reverseMap.containsKey(value);
  563.     }

  564.     /**
  565.      * Creates a new instance of the subclass.
  566.      *
  567.      * @param normalMap  the normal direction map
  568.      * @param reverseMap  the reverse direction map
  569.      * @param inverseMap  this map, which is the inverse in the new map
  570.      * @return the bidi map
  571.      */
  572.     protected abstract BidiMap<V, K> createBidiMap(Map<V, K> normalMap, Map<K, V> reverseMap, BidiMap<K, V> inverseMap);

  573.     /**
  574.      * Creates an entry set iterator.
  575.      * Subclasses can override this to return iterators with different properties.
  576.      *
  577.      * @param iterator  the iterator to decorate
  578.      * @return the entrySet iterator
  579.      */
  580.     protected Iterator<Map.Entry<K, V>> createEntrySetIterator(final Iterator<Map.Entry<K, V>> iterator) {
  581.         return new EntrySetIterator<>(iterator, this);
  582.     }

  583.     /**
  584.      * Creates a key set iterator.
  585.      * Subclasses can override this to return iterators with different properties.
  586.      *
  587.      * @param iterator  the iterator to decorate
  588.      * @return the keySet iterator
  589.      */
  590.     protected Iterator<K> createKeySetIterator(final Iterator<K> iterator) {
  591.         return new KeySetIterator<>(iterator, this);
  592.     }

  593.     /**
  594.      * Creates a values iterator.
  595.      * Subclasses can override this to return iterators with different properties.
  596.      *
  597.      * @param iterator  the iterator to decorate
  598.      * @return the values iterator
  599.      */
  600.     protected Iterator<V> createValuesIterator(final Iterator<V> iterator) {
  601.         return new ValuesIterator<>(iterator, this);
  602.     }

  603.     /**
  604.      * Gets an entrySet view of the map.
  605.      * Changes made on the set are reflected in the map.
  606.      * The set supports remove and clear but not add.
  607.      * <p>
  608.      * The Map Entry setValue() method only allow a new value to be set.
  609.      * If the value being set is already in the map, an IllegalArgumentException
  610.      * is thrown (as setValue cannot change the size of the map).
  611.      * </p>
  612.      *
  613.      * @return the entrySet view
  614.      */
  615.     @Override
  616.     public Set<Map.Entry<K, V>> entrySet() {
  617.         if (entrySet == null) {
  618.             entrySet = new EntrySet<>(this);
  619.         }
  620.         return entrySet;
  621.     }

  622.     @Override
  623.     public boolean equals(final Object obj) {
  624.         return normalMap.equals(obj);
  625.     }

  626.     @Override
  627.     public V get(final Object key) {
  628.         return normalMap.get(key);
  629.     }

  630.     @Override
  631.     public K getKey(final Object value) {
  632.         return reverseMap.get(value);
  633.     }

  634.     @Override
  635.     public int hashCode() {
  636.         return normalMap.hashCode();
  637.     }

  638.     @Override
  639.     public BidiMap<V, K> inverseBidiMap() {
  640.         if (inverseBidiMap == null) {
  641.             inverseBidiMap = createBidiMap(reverseMap, normalMap, this);
  642.         }
  643.         return inverseBidiMap;
  644.     }

  645.     @Override
  646.     public boolean isEmpty() {
  647.         return normalMap.isEmpty();
  648.     }

  649.     // Map views
  650.     /**
  651.      * Gets a keySet view of the map.
  652.      * Changes made on the view are reflected in the map.
  653.      * The set supports remove and clear but not add.
  654.      *
  655.      * @return the keySet view
  656.      */
  657.     @Override
  658.     public Set<K> keySet() {
  659.         if (keySet == null) {
  660.             keySet = new KeySet<>(this);
  661.         }
  662.         return keySet;
  663.     }

  664.     // BidiMap
  665.     /**
  666.      * Obtains a {@code MapIterator} over the map.
  667.      * The iterator implements {@link BidiMapIterator}.
  668.      * This implementation relies on the entrySet iterator.
  669.      *
  670.      * @return a map iterator
  671.      */
  672.     @Override
  673.     public MapIterator<K, V> mapIterator() {
  674.         return new BidiMapIterator<>(this);
  675.     }

  676.     @Override
  677.     public V put(final K key, final V value) {
  678.         if (normalMap.containsKey(key)) {
  679.             reverseMap.remove(normalMap.get(key));
  680.         }
  681.         if (reverseMap.containsKey(value)) {
  682.             normalMap.remove(reverseMap.get(value));
  683.         }
  684.         final V obj = normalMap.put(key, value);
  685.         reverseMap.put(value, key);
  686.         return obj;
  687.     }

  688.     @Override
  689.     public void putAll(final Map<? extends K, ? extends V> map) {
  690.         for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
  691.             put(entry.getKey(), entry.getValue());
  692.         }
  693.     }

  694.     @Override
  695.     public V remove(final Object key) {
  696.         V value = null;
  697.         if (normalMap.containsKey(key)) {
  698.             value = normalMap.remove(key);
  699.             reverseMap.remove(value);
  700.         }
  701.         return value;
  702.     }

  703.     @Override
  704.     public K removeValue(final Object value) {
  705.         K key = null;
  706.         if (reverseMap.containsKey(value)) {
  707.             key = reverseMap.remove(value);
  708.             normalMap.remove(key);
  709.         }
  710.         return key;
  711.     }

  712.     @Override
  713.     public int size() {
  714.         return normalMap.size();
  715.     }

  716.     @Override
  717.     public String toString() {
  718.         return normalMap.toString();
  719.     }

  720.     /**
  721.      * Gets a values view of the map.
  722.      * Changes made on the view are reflected in the map.
  723.      * The set supports remove and clear but not add.
  724.      *
  725.      * @return the values view
  726.      */
  727.     @Override
  728.     public Set<V> values() {
  729.         if (values == null) {
  730.             values = new Values<>(this);
  731.         }
  732.         return values;
  733.     }

  734. }