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