    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 *      https://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 */
    017
    018package org.apache.commons.collections4;
    019
    020import java.util.Collection;
    021import java.util.Map;
    022import java.util.Map.Entry;
    023import java.util.Set;
    024
    025/**
    026 * Defines a map that holds a collection of values against each key.
    027 * <p>
    028 * A {@code MultiValuedMap} is a Map with slightly different semantics:
    029 * </p>
    030 * <ul>
    031 * <li>Putting a value into the map will add the value to a {@link Collection} at that key.</li>
    032 * <li>Getting a value will return a {@link Collection}, holding all the values put to that key.</li>
    033 * </ul>
    034 * <p>
    035 * For example:
    036 * </p>
    037 *
    038 * <pre>{@code
    039 * MultiValuedMap<Integer, String> map = new ArrayListValuedHashMap<>();
    040 * map.put(1, "A");
    041 * map.put(1, "B");
    042 * map.put(1, "C");
    043 * Collection<String> coll = map.get(1);
    044 * }</pre>
    045 * <p>
    046 * {@code coll} will be a collection containing "A", "B", "C".
    047 * </p>
    048 *
    049 * @param <K> The type of the keys in this map
    050 * @param <V> The type of the values in this map
    051 * @since 4.1
    052 */
    053public interface MultiValuedMap<K, V> {
    054    // Query operations
    055
    056    /**
    057     * Returns a view of this multivalued map as a {@code Map} from each distinct key to the non-empty collection of that key's associated values.
    058     * <p>
    059     * Note that {@code this.asMap().get(k)} is equivalent to {@code this.get(k)} only when {@code k} is a key contained in the multivalued map; otherwise it
    060     * returns {@code null} as opposed to an empty collection.
    061     * </p>
    062     * <p>
    063     * Changes to the returned map or the collections that serve as its values will update the underlying multivalued map, and vice versa. The map does not
    064     * support {@code put} or {@code putAll}, nor do its entries support {@link java.util.Map.Entry#setValue(Object) setValue}.
    065     * </p>
    066     *
    067     * @return A map view of the mappings in this multivalued map.
    068     */
    069    Map<K, Collection<V>> asMap();
    070
    071    /**
    072     * Removes all of the mappings from this map (optional operation).
    073     * <p>
    074     * The map will be empty after this call returns.
    075     * </p>
    076     *
    077     * @throws UnsupportedOperationException if the map is unmodifiable.
    078     */
    079    void clear();
    080
    081    /**
    082     * Returns {@code true} if this map contains a mapping for the specified key. More formally, returns {@code true} if and only if this map contains a mapping
    083     * for a key {@code k} such that {@code (key==null ? k==null : key.equals(k))}. (There can be at most one such mapping.)
    084     *
    085     * @param key key whose presence in this map is to be tested.
    086     * @return true if this map contains a mapping for the specified key.
    087     * @throws NullPointerException if the specified key is null and this map does not permit null keys (optional).
    088     */
    089    boolean containsKey(Object key);
    090
    091    /**
    092     * Checks whether the map contains a mapping for the specified key and value.
    093     *
    094     * @param key   The key to search for.
    095     * @param value The value to search for.
    096     * @return true if the map contains the value.
    097     */
    098    boolean containsMapping(Object key, Object value);
    099
    100    /**
    101     * Checks whether the map contains at least one mapping for the specified value.
    102     *
    103     * @param value The value to search for.
    104     * @return true if the map contains the value.
    105     * @throws NullPointerException if the value is null and null values are not supported by the used collection types (optional).
    106     */
    107    boolean containsValue(Object value);
    108
    109    /**
    110     * Returns a {@link Collection} view of the mappings contained in this multivalued map.
    111     * <p>
    112     * The collection is backed by the map, so changes to the map are reflected in the collection, and vice-versa.
    113     * </p>
    114     *
    115     * @return A set view of the mappings contained in this map.
    116     */
    117    Collection<Entry<K, V>> entries();
    118    // Modification operations
    119
    120    /**
    121     * Gets a view collection of the values associated with the specified key.
    122     * <p>
    123     * This method will return an <strong>empty</strong> collection if {@link #containsKey(Object)} returns {@code false}. Changes to the returned collection
    124     * will update the underlying {@code MultiValuedMap} and vice-versa.
    125     * </p>
    126     *
    127     * @param key The key to retrieve.
    128     * @return The {@code Collection} of values, implementations should return an empty collection for no mapping.
    129     * @throws NullPointerException if the key is null and null keys are invalid (optional).
    130     */
    131    Collection<V> get(K key);
    132
    133    /**
    134     * Always throws {@link UnsupportedOperationException}.
    135     *
    136     * @return Always throws {@link UnsupportedOperationException}.
    137     * @throws UnsupportedOperationException Always thrown.
    138     * @since 4.6.0
    139     */
    140    default MultiValuedMap<V, K> inverted() {
    141        throw new UnsupportedOperationException(getClass() + ".inverted()");
    142    }
    143
    144    /**
    145     * Returns {@code true} if this map contains no key-value mappings.
    146     *
    147     * @return {@code true} if this map contains no key-value mappings.
    148     */
    149    boolean isEmpty();
    150
    151    /**
    152     * Returns a {@link MultiSet} view of the keys contained in this multivalued map.
    153     * <p>
    154     * The {@link MultiSet#getCount(Object)} method of the returned multiset will give the same result a calling {@code get(Object).size()} for the same key.
    155     * </p>
    156     * <p>
    157     * This multiset is backed by the map, so any changes in the map are reflected in the multiset.
    158     * </p>
    159     *
    160     * @return A multiset view of the keys contained in this map.
    161     */
    162    MultiSet<K> keys();
    163
    164    /**
    165     * Returns a {@link Set} view of the keys contained in this multivalued map.
    166     * <p>
    167     * The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.
    168     * </p>
    169     * <p>
    170     * If the map is modified while an iteration over the set is in progress (except through the iterator's own {@code remove} operation), the result of the
    171     * iteration is undefined. The set supports element removal, which removes the corresponding mapping from the map, via the {@code Iterator.remove},
    172     * {@code Set.remove}, {@code removeAll}, {@code retainAll}, and {@code clear} operations. It does not support the {@code add} or {@code addAll} operations.
    173     * </p>
    174     *
    175     * @return A set view of the keys contained in this map.
    176     */
    177    Set<K> keySet();
    178
    179    /**
    180     * Obtains a {@code MapIterator} over this multivalued map.
    181     * <p>
    182     * A map iterator is an efficient way of iterating over maps. There is no need to access the entries collection or use {@code Map.Entry} objects.
    183     * </p>
    184     *
    185     * @return A map iterator.
    186     */
    187    MapIterator<K, V> mapIterator();
    188
    189    /**
    190     * Adds a key-value mapping to this multivalued map.
    191     * <p>
    192     * Unlike a normal {@code Map} the previous value is not replaced. Instead, the new value is added to the collection stored against the key. Depending on
    193     * the collection type used, duplicate key-value mappings may be allowed.
    194     * </p>
    195     * <p>
    196     * The method will return {@code true} if the size of the multivalued map has been increased because of this operation.
    197     * </p>
    198     *
    199     * @param key   The key to store against.
    200     * @param value The value to add to the collection at the key.
    201     * @return true if the map changed as a result of this put operation, or false if the map already contained the key-value mapping and the collection type
    202     *         does not allow duplicate values, for example when using a Set.
    203     * @throws UnsupportedOperationException if the put operation is not supported by this multivalued map, for example if it is unmodifiable.
    204     * @throws NullPointerException          if the key or value is null and null is invalid (optional).
    205     * @throws IllegalArgumentException      if some aspect of the specified key or value prevents it from being stored in this multivalued map.
    206     */
    207    boolean put(K key, V value);
    208
    209    /**
    210     * Adds a mapping to the specified key for all values contained in the given Iterable.
    211     *
    212     * @param key    The key to store against.
    213     * @param values The values to add to the collection at the key, may not be null.
    214     * @return true if the map changed as a result of this operation.
    215     * @throws NullPointerException if the specified iterable is null, or if this map does not permit null keys or values, and the specified key or values
    216     *                              contain null (optional).
    217     */
    218    boolean putAll(K key, Iterable<? extends V> values);
    219
    220    /**
    221     * Copies all mappings from the specified map to this multivalued map (optional operation).
    222     * <p>
    223     * The effect of this call is equivalent to that of calling {@link #put(Object,Object) put(k, v)} on this map once for each mapping from key {@code k} to
    224     * value {@code v} in the specified map.
    225     * </p>
    226     * <p>
    227     * The behavior of this operation is undefined if the specified map is modified while the operation is in progress.
    228     * </p>
    229     *
    230     * @param map mappings to be stored in this map, may not be null.
    231     * @return true if the map changed as a result of this operation.
    232     * @throws UnsupportedOperationException if the {@code putAll} operation is not supported by this map.
    233     * @throws NullPointerException          if the specified map is null, or if this map does not permit null keys or values, and the specified map contains
    234     *                                       null keys or values (optional).
    235     * @throws IllegalArgumentException      if some property of a key or value in the specified map prevents it from being stored in this map.
    236     */
    237    boolean putAll(Map<? extends K, ? extends V> map);
    238
    239    /**
    240     * Copies all mappings from the specified map to this multivalued map (optional operation).
    241     * <p>
    242     * The effect of this call is equivalent to that of calling {@link #put(Object,Object) put(k, v)} on this map once for each mapping from key {@code k} to
    243     * value {@code v} in the specified map.
    244     * </p>
    245     * <p>
    246     * The behavior of this operation is undefined if the specified map is modified while the operation is in progress.
    247     * </p>
    248     *
    249     * @param map mappings to be stored in this map, may not be null.
    250     * @return true if the map changed as a result of this operation.
    251     * @throws UnsupportedOperationException if the {@code putAll} operation is not supported by this map.
    252     * @throws NullPointerException          if the specified map is null, or if this map does not permit null keys or values, and the specified map contains
    253     *                                       null keys or values (optional).
    254     * @throws IllegalArgumentException      if some property of a key or value in the specified map prevents it from being stored in this map.
    255     */
    256    boolean putAll(MultiValuedMap<? extends K, ? extends V> map);
    257
    258    /**
    259     * Removes all values associated with the specified key.
    260     * <p>
    261     * The returned collection <em>may</em> be modifiable, but updates will not be propagated to this multivalued map. In case no mapping was stored for the
    262     * specified key, an empty, unmodifiable collection will be returned.
    263     * </p>
    264     *
    265     * @param key The key to remove values from.
    266     * @return The values that were removed.
    267     * @throws UnsupportedOperationException if the map is unmodifiable.
    268     * @throws NullPointerException          if the key is null and null keys are invalid (optional).
    269     */
    270    Collection<V> remove(Object key);
    271
    272    /**
    273     * Removes a key-value mapping from the map.
    274     * <p>
    275     * The item is removed from the collection mapped to the specified key. Other values attached to that key are unaffected.
    276     * </p>
    277     * <p>
    278     * If the last value for a key is removed, implementations typically return an empty collection from a subsequent {@code get(Object)}.
    279     * </p>
    280     *
    281     * @param key  The key to remove from.
    282     * @param item The item to remove.
    283     * @return true if the mapping was removed, false otherwise.
    284     * @throws UnsupportedOperationException if the map is unmodifiable.
    285     * @throws NullPointerException          if the key or value is null and null is invalid (optional).
    286     */
    287    boolean removeMapping(Object key, Object item);
    288
    289    /**
    290     * Gets the total size of the map.
    291     * <p>
    292     * Implementations would return the total size of the map which is the count of the values from all keys.
    293     * </p>
    294     *
    295     * @return The total size of the map.
    296     */
    297    int size();
    298
    299    /**
    300     * Gets a {@link Collection} view of all values contained in this multivalued map.
    301     * <p>
    302     * Implementations typically return a collection containing the combination of values from all keys.
    303     * </p>
    304     *
    305     * @return A collection view of the values contained in this multivalued map.
    306     */
    307    Collection<V> values();
    308}