
javadoc.src-html.com.google.common.collect.Multimaps.html Maven / Gradle / Ivy
The newest version!
001 /*
002 * Copyright (C) 2007 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package com.google.common.collect;
018
019 import static com.google.common.base.Preconditions.checkArgument;
020 import static com.google.common.base.Preconditions.checkNotNull;
021 import static com.google.common.base.Preconditions.checkState;
022
023 import com.google.common.annotations.Beta;
024 import com.google.common.annotations.GwtCompatible;
025 import com.google.common.annotations.GwtIncompatible;
026 import com.google.common.base.Function;
027 import com.google.common.base.Joiner;
028 import com.google.common.base.Joiner.MapJoiner;
029 import com.google.common.base.Objects;
030 import com.google.common.base.Predicate;
031 import com.google.common.base.Predicates;
032 import com.google.common.base.Supplier;
033 import com.google.common.collect.Collections2.TransformedCollection;
034 import com.google.common.collect.Maps.EntryTransformer;
035
036 import java.io.IOException;
037 import java.io.ObjectInputStream;
038 import java.io.ObjectOutputStream;
039 import java.io.Serializable;
040 import java.util.AbstractCollection;
041 import java.util.AbstractSet;
042 import java.util.Collection;
043 import java.util.Collections;
044 import java.util.Comparator;
045 import java.util.HashSet;
046 import java.util.Iterator;
047 import java.util.List;
048 import java.util.Map;
049 import java.util.Map.Entry;
050 import java.util.NoSuchElementException;
051 import java.util.Set;
052 import java.util.SortedSet;
053
054 import javax.annotation.Nullable;
055
056 /**
057 * Provides static methods acting on or generating a {@code Multimap}.
058 *
059 * @author Jared Levy
060 * @author Robert Konigsberg
061 * @author Mike Bostock
062 * @author Louis Wasserman
063 * @since 2.0 (imported from Google Collections Library)
064 */
065 @GwtCompatible(emulated = true)
066 public final class Multimaps {
067 private Multimaps() {}
068
069 /**
070 * Creates a new {@code Multimap} that uses the provided map and factory. It
071 * can generate a multimap based on arbitrary {@link Map} and
072 * {@link Collection} classes.
073 *
074 * <p>The {@code factory}-generated and {@code map} classes determine the
075 * multimap iteration order. They also specify the behavior of the
076 * {@code equals}, {@code hashCode}, and {@code toString} methods for the
077 * multimap and its returned views. However, the multimap's {@code get}
078 * method returns instances of a different class than {@code factory.get()}
079 * does.
080 *
081 * <p>The multimap is serializable if {@code map}, {@code factory}, the
082 * collections generated by {@code factory}, and the multimap contents are all
083 * serializable.
084 *
085 * <p>The multimap is not threadsafe when any concurrent operations update the
086 * multimap, even if {@code map} and the instances generated by
087 * {@code factory} are. Concurrent read operations will work correctly. To
088 * allow concurrent update operations, wrap the multimap with a call to
089 * {@link #synchronizedMultimap}.
090 *
091 * <p>Call this method only when the simpler methods
092 * {@link ArrayListMultimap#create()}, {@link HashMultimap#create()},
093 * {@link LinkedHashMultimap#create()}, {@link LinkedListMultimap#create()},
094 * {@link TreeMultimap#create()}, and
095 * {@link TreeMultimap#create(Comparator, Comparator)} won't suffice.
096 *
097 * <p>Note: the multimap assumes complete ownership over of {@code map} and
098 * the collections returned by {@code factory}. Those objects should not be
099 * manually updated and they should not use soft, weak, or phantom references.
100 *
101 * @param map place to store the mapping from each key to its corresponding
102 * values
103 * @param factory supplier of new, empty collections that will each hold all
104 * values for a given key
105 * @throws IllegalArgumentException if {@code map} is not empty
106 */
107 public static <K, V> Multimap<K, V> newMultimap(Map<K, Collection<V>> map,
108 final Supplier<? extends Collection<V>> factory) {
109 return new CustomMultimap<K, V>(map, factory);
110 }
111
112 private static class CustomMultimap<K, V> extends AbstractMultimap<K, V> {
113 transient Supplier<? extends Collection<V>> factory;
114
115 CustomMultimap(Map<K, Collection<V>> map,
116 Supplier<? extends Collection<V>> factory) {
117 super(map);
118 this.factory = checkNotNull(factory);
119 }
120
121 @Override protected Collection<V> createCollection() {
122 return factory.get();
123 }
124
125 // can't use Serialization writeMultimap and populateMultimap methods since
126 // there's no way to generate the empty backing map.
127
128 /** @serialData the factory and the backing map */
129 @GwtIncompatible("java.io.ObjectOutputStream")
130 private void writeObject(ObjectOutputStream stream) throws IOException {
131 stream.defaultWriteObject();
132 stream.writeObject(factory);
133 stream.writeObject(backingMap());
134 }
135
136 @GwtIncompatible("java.io.ObjectInputStream")
137 @SuppressWarnings("unchecked") // reading data stored by writeObject
138 private void readObject(ObjectInputStream stream)
139 throws IOException, ClassNotFoundException {
140 stream.defaultReadObject();
141 factory = (Supplier<? extends Collection<V>>) stream.readObject();
142 Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject();
143 setMap(map);
144 }
145
146 @GwtIncompatible("java serialization not supported")
147 private static final long serialVersionUID = 0;
148 }
149
150 /**
151 * Creates a new {@code ListMultimap} that uses the provided map and factory.
152 * It can generate a multimap based on arbitrary {@link Map} and {@link List}
153 * classes.
154 *
155 * <p>The {@code factory}-generated and {@code map} classes determine the
156 * multimap iteration order. They also specify the behavior of the
157 * {@code equals}, {@code hashCode}, and {@code toString} methods for the
158 * multimap and its returned views. The multimap's {@code get}, {@code
159 * removeAll}, and {@code replaceValues} methods return {@code RandomAccess}
160 * lists if the factory does. However, the multimap's {@code get} method
161 * returns instances of a different class than does {@code factory.get()}.
162 *
163 * <p>The multimap is serializable if {@code map}, {@code factory}, the
164 * lists generated by {@code factory}, and the multimap contents are all
165 * serializable.
166 *
167 * <p>The multimap is not threadsafe when any concurrent operations update the
168 * multimap, even if {@code map} and the instances generated by
169 * {@code factory} are. Concurrent read operations will work correctly. To
170 * allow concurrent update operations, wrap the multimap with a call to
171 * {@link #synchronizedListMultimap}.
172 *
173 * <p>Call this method only when the simpler methods
174 * {@link ArrayListMultimap#create()} and {@link LinkedListMultimap#create()}
175 * won't suffice.
176 *
177 * <p>Note: the multimap assumes complete ownership over of {@code map} and
178 * the lists returned by {@code factory}. Those objects should not be manually
179 * updated, they should be empty when provided, and they should not use soft,
180 * weak, or phantom references.
181 *
182 * @param map place to store the mapping from each key to its corresponding
183 * values
184 * @param factory supplier of new, empty lists that will each hold all values
185 * for a given key
186 * @throws IllegalArgumentException if {@code map} is not empty
187 */
188 public static <K, V> ListMultimap<K, V> newListMultimap(
189 Map<K, Collection<V>> map, final Supplier<? extends List<V>> factory) {
190 return new CustomListMultimap<K, V>(map, factory);
191 }
192
193 private static class CustomListMultimap<K, V>
194 extends AbstractListMultimap<K, V> {
195 transient Supplier<? extends List<V>> factory;
196
197 CustomListMultimap(Map<K, Collection<V>> map,
198 Supplier<? extends List<V>> factory) {
199 super(map);
200 this.factory = checkNotNull(factory);
201 }
202
203 @Override protected List<V> createCollection() {
204 return factory.get();
205 }
206
207 /** @serialData the factory and the backing map */
208 @GwtIncompatible("java.io.ObjectOutputStream")
209 private void writeObject(ObjectOutputStream stream) throws IOException {
210 stream.defaultWriteObject();
211 stream.writeObject(factory);
212 stream.writeObject(backingMap());
213 }
214
215 @GwtIncompatible("java.io.ObjectInputStream")
216 @SuppressWarnings("unchecked") // reading data stored by writeObject
217 private void readObject(ObjectInputStream stream)
218 throws IOException, ClassNotFoundException {
219 stream.defaultReadObject();
220 factory = (Supplier<? extends List<V>>) stream.readObject();
221 Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject();
222 setMap(map);
223 }
224
225 @GwtIncompatible("java serialization not supported")
226 private static final long serialVersionUID = 0;
227 }
228
229 /**
230 * Creates a new {@code SetMultimap} that uses the provided map and factory.
231 * It can generate a multimap based on arbitrary {@link Map} and {@link Set}
232 * classes.
233 *
234 * <p>The {@code factory}-generated and {@code map} classes determine the
235 * multimap iteration order. They also specify the behavior of the
236 * {@code equals}, {@code hashCode}, and {@code toString} methods for the
237 * multimap and its returned views. However, the multimap's {@code get}
238 * method returns instances of a different class than {@code factory.get()}
239 * does.
240 *
241 * <p>The multimap is serializable if {@code map}, {@code factory}, the
242 * sets generated by {@code factory}, and the multimap contents are all
243 * serializable.
244 *
245 * <p>The multimap is not threadsafe when any concurrent operations update the
246 * multimap, even if {@code map} and the instances generated by
247 * {@code factory} are. Concurrent read operations will work correctly. To
248 * allow concurrent update operations, wrap the multimap with a call to
249 * {@link #synchronizedSetMultimap}.
250 *
251 * <p>Call this method only when the simpler methods
252 * {@link HashMultimap#create()}, {@link LinkedHashMultimap#create()},
253 * {@link TreeMultimap#create()}, and
254 * {@link TreeMultimap#create(Comparator, Comparator)} won't suffice.
255 *
256 * <p>Note: the multimap assumes complete ownership over of {@code map} and
257 * the sets returned by {@code factory}. Those objects should not be manually
258 * updated and they should not use soft, weak, or phantom references.
259 *
260 * @param map place to store the mapping from each key to its corresponding
261 * values
262 * @param factory supplier of new, empty sets that will each hold all values
263 * for a given key
264 * @throws IllegalArgumentException if {@code map} is not empty
265 */
266 public static <K, V> SetMultimap<K, V> newSetMultimap(
267 Map<K, Collection<V>> map, final Supplier<? extends Set<V>> factory) {
268 return new CustomSetMultimap<K, V>(map, factory);
269 }
270
271 private static class CustomSetMultimap<K, V>
272 extends AbstractSetMultimap<K, V> {
273 transient Supplier<? extends Set<V>> factory;
274
275 CustomSetMultimap(Map<K, Collection<V>> map,
276 Supplier<? extends Set<V>> factory) {
277 super(map);
278 this.factory = checkNotNull(factory);
279 }
280
281 @Override protected Set<V> createCollection() {
282 return factory.get();
283 }
284
285 /** @serialData the factory and the backing map */
286 @GwtIncompatible("java.io.ObjectOutputStream")
287 private void writeObject(ObjectOutputStream stream) throws IOException {
288 stream.defaultWriteObject();
289 stream.writeObject(factory);
290 stream.writeObject(backingMap());
291 }
292
293 @GwtIncompatible("java.io.ObjectInputStream")
294 @SuppressWarnings("unchecked") // reading data stored by writeObject
295 private void readObject(ObjectInputStream stream)
296 throws IOException, ClassNotFoundException {
297 stream.defaultReadObject();
298 factory = (Supplier<? extends Set<V>>) stream.readObject();
299 Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject();
300 setMap(map);
301 }
302
303 @GwtIncompatible("not needed in emulated source")
304 private static final long serialVersionUID = 0;
305 }
306
307 /**
308 * Creates a new {@code SortedSetMultimap} that uses the provided map and
309 * factory. It can generate a multimap based on arbitrary {@link Map} and
310 * {@link SortedSet} classes.
311 *
312 * <p>The {@code factory}-generated and {@code map} classes determine the
313 * multimap iteration order. They also specify the behavior of the
314 * {@code equals}, {@code hashCode}, and {@code toString} methods for the
315 * multimap and its returned views. However, the multimap's {@code get}
316 * method returns instances of a different class than {@code factory.get()}
317 * does.
318 *
319 * <p>The multimap is serializable if {@code map}, {@code factory}, the
320 * sets generated by {@code factory}, and the multimap contents are all
321 * serializable.
322 *
323 * <p>The multimap is not threadsafe when any concurrent operations update the
324 * multimap, even if {@code map} and the instances generated by
325 * {@code factory} are. Concurrent read operations will work correctly. To
326 * allow concurrent update operations, wrap the multimap with a call to
327 * {@link #synchronizedSortedSetMultimap}.
328 *
329 * <p>Call this method only when the simpler methods
330 * {@link TreeMultimap#create()} and
331 * {@link TreeMultimap#create(Comparator, Comparator)} won't suffice.
332 *
333 * <p>Note: the multimap assumes complete ownership over of {@code map} and
334 * the sets returned by {@code factory}. Those objects should not be manually
335 * updated and they should not use soft, weak, or phantom references.
336 *
337 * @param map place to store the mapping from each key to its corresponding
338 * values
339 * @param factory supplier of new, empty sorted sets that will each hold
340 * all values for a given key
341 * @throws IllegalArgumentException if {@code map} is not empty
342 */
343 public static <K, V> SortedSetMultimap<K, V> newSortedSetMultimap(
344 Map<K, Collection<V>> map,
345 final Supplier<? extends SortedSet<V>> factory) {
346 return new CustomSortedSetMultimap<K, V>(map, factory);
347 }
348
349 private static class CustomSortedSetMultimap<K, V>
350 extends AbstractSortedSetMultimap<K, V> {
351 transient Supplier<? extends SortedSet<V>> factory;
352 transient Comparator<? super V> valueComparator;
353
354 CustomSortedSetMultimap(Map<K, Collection<V>> map,
355 Supplier<? extends SortedSet<V>> factory) {
356 super(map);
357 this.factory = checkNotNull(factory);
358 valueComparator = factory.get().comparator();
359 }
360
361 @Override protected SortedSet<V> createCollection() {
362 return factory.get();
363 }
364
365 @Override public Comparator<? super V> valueComparator() {
366 return valueComparator;
367 }
368
369 /** @serialData the factory and the backing map */
370 @GwtIncompatible("java.io.ObjectOutputStream")
371 private void writeObject(ObjectOutputStream stream) throws IOException {
372 stream.defaultWriteObject();
373 stream.writeObject(factory);
374 stream.writeObject(backingMap());
375 }
376
377 @GwtIncompatible("java.io.ObjectInputStream")
378 @SuppressWarnings("unchecked") // reading data stored by writeObject
379 private void readObject(ObjectInputStream stream)
380 throws IOException, ClassNotFoundException {
381 stream.defaultReadObject();
382 factory = (Supplier<? extends SortedSet<V>>) stream.readObject();
383 valueComparator = factory.get().comparator();
384 Map<K, Collection<V>> map = (Map<K, Collection<V>>) stream.readObject();
385 setMap(map);
386 }
387
388 @GwtIncompatible("not needed in emulated source")
389 private static final long serialVersionUID = 0;
390 }
391
392 /**
393 * Copies each key-value mapping in {@code source} into {@code dest}, with
394 * its key and value reversed.
395 *
396 * <p>If {@code source} is an {@link ImmutableMultimap}, consider using
397 * {@link ImmutableMultimap#inverse} instead.
398 *
399 * @param source any multimap
400 * @param dest the multimap to copy into; usually empty
401 * @return {@code dest}
402 */
403 public static <K, V, M extends Multimap<K, V>> M invertFrom(
404 Multimap<? extends V, ? extends K> source, M dest) {
405 checkNotNull(dest);
406 for (Map.Entry<? extends V, ? extends K> entry : source.entries()) {
407 dest.put(entry.getValue(), entry.getKey());
408 }
409 return dest;
410 }
411
412 /**
413 * Returns a synchronized (thread-safe) multimap backed by the specified
414 * multimap. In order to guarantee serial access, it is critical that
415 * <b>all</b> access to the backing multimap is accomplished through the
416 * returned multimap.
417 *
418 * <p>It is imperative that the user manually synchronize on the returned
419 * multimap when accessing any of its collection views: <pre> {@code
420 *
421 * Multimap<K, V> m = Multimaps.synchronizedMultimap(
422 * HashMultimap.<K, V>create());
423 * ...
424 * Set<K> s = m.keySet(); // Needn't be in synchronized block
425 * ...
426 * synchronized (m) { // Synchronizing on m, not s!
427 * Iterator<K> i = s.iterator(); // Must be in synchronized block
428 * while (i.hasNext()) {
429 * foo(i.next());
430 * }
431 * }}</pre>
432 *
433 * Failure to follow this advice may result in non-deterministic behavior.
434 *
435 * <p>Note that the generated multimap's {@link Multimap#removeAll} and
436 * {@link Multimap#replaceValues} methods return collections that aren't
437 * synchronized.
438 *
439 * <p>The returned multimap will be serializable if the specified multimap is
440 * serializable.
441 *
442 * @param multimap the multimap to be wrapped in a synchronized view
443 * @return a synchronized view of the specified multimap
444 */
445 public static <K, V> Multimap<K, V> synchronizedMultimap(
446 Multimap<K, V> multimap) {
447 return Synchronized.multimap(multimap, null);
448 }
449
450 /**
451 * Returns an unmodifiable view of the specified multimap. Query operations on
452 * the returned multimap "read through" to the specified multimap, and
453 * attempts to modify the returned multimap, either directly or through the
454 * multimap's views, result in an {@code UnsupportedOperationException}.
455 *
456 * <p>Note that the generated multimap's {@link Multimap#removeAll} and
457 * {@link Multimap#replaceValues} methods return collections that are
458 * modifiable.
459 *
460 * <p>The returned multimap will be serializable if the specified multimap is
461 * serializable.
462 *
463 * @param delegate the multimap for which an unmodifiable view is to be
464 * returned
465 * @return an unmodifiable view of the specified multimap
466 */
467 public static <K, V> Multimap<K, V> unmodifiableMultimap(
468 Multimap<K, V> delegate) {
469 if (delegate instanceof UnmodifiableMultimap ||
470 delegate instanceof ImmutableMultimap) {
471 return delegate;
472 }
473 return new UnmodifiableMultimap<K, V>(delegate);
474 }
475
476 /**
477 * Simply returns its argument.
478 *
479 * @deprecated no need to use this
480 * @since 10.0
481 */
482 @Deprecated public static <K, V> Multimap<K, V> unmodifiableMultimap(
483 ImmutableMultimap<K, V> delegate) {
484 return checkNotNull(delegate);
485 }
486
487 private static class UnmodifiableMultimap<K, V>
488 extends ForwardingMultimap<K, V> implements Serializable {
489 final Multimap<K, V> delegate;
490 transient Collection<Entry<K, V>> entries;
491 transient Multiset<K> keys;
492 transient Set<K> keySet;
493 transient Collection<V> values;
494 transient Map<K, Collection<V>> map;
495
496 UnmodifiableMultimap(final Multimap<K, V> delegate) {
497 this.delegate = checkNotNull(delegate);
498 }
499
500 @Override protected Multimap<K, V> delegate() {
501 return delegate;
502 }
503
504 @Override public void clear() {
505 throw new UnsupportedOperationException();
506 }
507
508 @Override public Map<K, Collection<V>> asMap() {
509 Map<K, Collection<V>> result = map;
510 if (result == null) {
511 final Map<K, Collection<V>> unmodifiableMap
512 = Collections.unmodifiableMap(delegate.asMap());
513 map = result = new ForwardingMap<K, Collection<V>>() {
514 @Override protected Map<K, Collection<V>> delegate() {
515 return unmodifiableMap;
516 }
517
518 Set<Entry<K, Collection<V>>> entrySet;
519
520 @Override public Set<Map.Entry<K, Collection<V>>> entrySet() {
521 Set<Entry<K, Collection<V>>> result = entrySet;
522 return (result == null)
523 ? entrySet
524 = unmodifiableAsMapEntries(unmodifiableMap.entrySet())
525 : result;
526 }
527
528 @Override public Collection<V> get(Object key) {
529 Collection<V> collection = unmodifiableMap.get(key);
530 return (collection == null)
531 ? null : unmodifiableValueCollection(collection);
532 }
533
534 Collection<Collection<V>> asMapValues;
535
536 @Override public Collection<Collection<V>> values() {
537 Collection<Collection<V>> result = asMapValues;
538 return (result == null)
539 ? asMapValues
540 = new UnmodifiableAsMapValues<V>(unmodifiableMap.values())
541 : result;
542 }
543
544 @Override public boolean containsValue(Object o) {
545 return values().contains(o);
546 }
547 };
548 }
549 return result;
550 }
551
552 @Override public Collection<Entry<K, V>> entries() {
553 Collection<Entry<K, V>> result = entries;
554 if (result == null) {
555 entries = result = unmodifiableEntries(delegate.entries());
556 }
557 return result;
558 }
559
560 @Override public Collection<V> get(K key) {
561 return unmodifiableValueCollection(delegate.get(key));
562 }
563
564 @Override public Multiset<K> keys() {
565 Multiset<K> result = keys;
566 if (result == null) {
567 keys = result = Multisets.unmodifiableMultiset(delegate.keys());
568 }
569 return result;
570 }
571
572 @Override public Set<K> keySet() {
573 Set<K> result = keySet;
574 if (result == null) {
575 keySet = result = Collections.unmodifiableSet(delegate.keySet());
576 }
577 return result;
578 }
579
580 @Override public boolean put(K key, V value) {
581 throw new UnsupportedOperationException();
582 }
583
584 @Override public boolean putAll(K key, Iterable<? extends V> values) {
585 throw new UnsupportedOperationException();
586 }
587
588 @Override
589 public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
590 throw new UnsupportedOperationException();
591 }
592
593 @Override public boolean remove(Object key, Object value) {
594 throw new UnsupportedOperationException();
595 }
596
597 @Override public Collection<V> removeAll(Object key) {
598 throw new UnsupportedOperationException();
599 }
600
601 @Override public Collection<V> replaceValues(
602 K key, Iterable<? extends V> values) {
603 throw new UnsupportedOperationException();
604 }
605
606 @Override public Collection<V> values() {
607 Collection<V> result = values;
608 if (result == null) {
609 values = result = Collections.unmodifiableCollection(delegate.values());
610 }
611 return result;
612 }
613
614 private static final long serialVersionUID = 0;
615 }
616
617 private static class UnmodifiableAsMapValues<V>
618 extends ForwardingCollection<Collection<V>> {
619 final Collection<Collection<V>> delegate;
620 UnmodifiableAsMapValues(Collection<Collection<V>> delegate) {
621 this.delegate = Collections.unmodifiableCollection(delegate);
622 }
623 @Override protected Collection<Collection<V>> delegate() {
624 return delegate;
625 }
626 @Override public Iterator<Collection<V>> iterator() {
627 final Iterator<Collection<V>> iterator = delegate.iterator();
628 return new Iterator<Collection<V>>() {
629 @Override
630 public boolean hasNext() {
631 return iterator.hasNext();
632 }
633 @Override
634 public Collection<V> next() {
635 return unmodifiableValueCollection(iterator.next());
636 }
637 @Override
638 public void remove() {
639 throw new UnsupportedOperationException();
640 }
641 };
642 }
643 @Override public Object[] toArray() {
644 return standardToArray();
645 }
646 @Override public <T> T[] toArray(T[] array) {
647 return standardToArray(array);
648 }
649 @Override public boolean contains(Object o) {
650 return standardContains(o);
651 }
652 @Override public boolean containsAll(Collection<?> c) {
653 return standardContainsAll(c);
654 }
655 }
656
657 private static class UnmodifiableListMultimap<K, V>
658 extends UnmodifiableMultimap<K, V> implements ListMultimap<K, V> {
659 UnmodifiableListMultimap(ListMultimap<K, V> delegate) {
660 super(delegate);
661 }
662 @Override public ListMultimap<K, V> delegate() {
663 return (ListMultimap<K, V>) super.delegate();
664 }
665 @Override public List<V> get(K key) {
666 return Collections.unmodifiableList(delegate().get(key));
667 }
668 @Override public List<V> removeAll(Object key) {
669 throw new UnsupportedOperationException();
670 }
671 @Override public List<V> replaceValues(
672 K key, Iterable<? extends V> values) {
673 throw new UnsupportedOperationException();
674 }
675 private static final long serialVersionUID = 0;
676 }
677
678 private static class UnmodifiableSetMultimap<K, V>
679 extends UnmodifiableMultimap<K, V> implements SetMultimap<K, V> {
680 UnmodifiableSetMultimap(SetMultimap<K, V> delegate) {
681 super(delegate);
682 }
683 @Override public SetMultimap<K, V> delegate() {
684 return (SetMultimap<K, V>) super.delegate();
685 }
686 @Override public Set<V> get(K key) {
687 /*
688 * Note that this doesn't return a SortedSet when delegate is a
689 * SortedSetMultiset, unlike (SortedSet<V>) super.get().
690 */
691 return Collections.unmodifiableSet(delegate().get(key));
692 }
693 @Override public Set<Map.Entry<K, V>> entries() {
694 return Maps.unmodifiableEntrySet(delegate().entries());
695 }
696 @Override public Set<V> removeAll(Object key) {
697 throw new UnsupportedOperationException();
698 }
699 @Override public Set<V> replaceValues(
700 K key, Iterable<? extends V> values) {
701 throw new UnsupportedOperationException();
702 }
703 private static final long serialVersionUID = 0;
704 }
705
706 private static class UnmodifiableSortedSetMultimap<K, V>
707 extends UnmodifiableSetMultimap<K, V> implements SortedSetMultimap<K, V> {
708 UnmodifiableSortedSetMultimap(SortedSetMultimap<K, V> delegate) {
709 super(delegate);
710 }
711 @Override public SortedSetMultimap<K, V> delegate() {
712 return (SortedSetMultimap<K, V>) super.delegate();
713 }
714 @Override public SortedSet<V> get(K key) {
715 return Collections.unmodifiableSortedSet(delegate().get(key));
716 }
717 @Override public SortedSet<V> removeAll(Object key) {
718 throw new UnsupportedOperationException();
719 }
720 @Override public SortedSet<V> replaceValues(
721 K key, Iterable<? extends V> values) {
722 throw new UnsupportedOperationException();
723 }
724 @Override
725 public Comparator<? super V> valueComparator() {
726 return delegate().valueComparator();
727 }
728 private static final long serialVersionUID = 0;
729 }
730
731 /**
732 * Returns a synchronized (thread-safe) {@code SetMultimap} backed by the
733 * specified multimap.
734 *
735 * <p>You must follow the warnings described in {@link #synchronizedMultimap}.
736 *
737 * <p>The returned multimap will be serializable if the specified multimap is
738 * serializable.
739 *
740 * @param multimap the multimap to be wrapped
741 * @return a synchronized view of the specified multimap
742 */
743 public static <K, V> SetMultimap<K, V> synchronizedSetMultimap(
744 SetMultimap<K, V> multimap) {
745 return Synchronized.setMultimap(multimap, null);
746 }
747
748 /**
749 * Returns an unmodifiable view of the specified {@code SetMultimap}. Query
750 * operations on the returned multimap "read through" to the specified
751 * multimap, and attempts to modify the returned multimap, either directly or
752 * through the multimap's views, result in an
753 * {@code UnsupportedOperationException}.
754 *
755 * <p>Note that the generated multimap's {@link Multimap#removeAll} and
756 * {@link Multimap#replaceValues} methods return collections that are
757 * modifiable.
758 *
759 * <p>The returned multimap will be serializable if the specified multimap is
760 * serializable.
761 *
762 * @param delegate the multimap for which an unmodifiable view is to be
763 * returned
764 * @return an unmodifiable view of the specified multimap
765 */
766 public static <K, V> SetMultimap<K, V> unmodifiableSetMultimap(
767 SetMultimap<K, V> delegate) {
768 if (delegate instanceof UnmodifiableSetMultimap ||
769 delegate instanceof ImmutableSetMultimap) {
770 return delegate;
771 }
772 return new UnmodifiableSetMultimap<K, V>(delegate);
773 }
774
775 /**
776 * Simply returns its argument.
777 *
778 * @deprecated no need to use this
779 * @since 10.0
780 */
781 @Deprecated public static <K, V> SetMultimap<K, V> unmodifiableSetMultimap(
782 ImmutableSetMultimap<K, V> delegate) {
783 return checkNotNull(delegate);
784 }
785
786 /**
787 * Returns a synchronized (thread-safe) {@code SortedSetMultimap} backed by
788 * the specified multimap.
789 *
790 * <p>You must follow the warnings described in {@link #synchronizedMultimap}.
791 *
792 * <p>The returned multimap will be serializable if the specified multimap is
793 * serializable.
794 *
795 * @param multimap the multimap to be wrapped
796 * @return a synchronized view of the specified multimap
797 */
798 public static <K, V> SortedSetMultimap<K, V>
799 synchronizedSortedSetMultimap(SortedSetMultimap<K, V> multimap) {
800 return Synchronized.sortedSetMultimap(multimap, null);
801 }
802
803 /**
804 * Returns an unmodifiable view of the specified {@code SortedSetMultimap}.
805 * Query operations on the returned multimap "read through" to the specified
806 * multimap, and attempts to modify the returned multimap, either directly or
807 * through the multimap's views, result in an
808 * {@code UnsupportedOperationException}.
809 *
810 * <p>Note that the generated multimap's {@link Multimap#removeAll} and
811 * {@link Multimap#replaceValues} methods return collections that are
812 * modifiable.
813 *
814 * <p>The returned multimap will be serializable if the specified multimap is
815 * serializable.
816 *
817 * @param delegate the multimap for which an unmodifiable view is to be
818 * returned
819 * @return an unmodifiable view of the specified multimap
820 */
821 public static <K, V> SortedSetMultimap<K, V> unmodifiableSortedSetMultimap(
822 SortedSetMultimap<K, V> delegate) {
823 if (delegate instanceof UnmodifiableSortedSetMultimap) {
824 return delegate;
825 }
826 return new UnmodifiableSortedSetMultimap<K, V>(delegate);
827 }
828
829 /**
830 * Returns a synchronized (thread-safe) {@code ListMultimap} backed by the
831 * specified multimap.
832 *
833 * <p>You must follow the warnings described in {@link #synchronizedMultimap}.
834 *
835 * @param multimap the multimap to be wrapped
836 * @return a synchronized view of the specified multimap
837 */
838 public static <K, V> ListMultimap<K, V> synchronizedListMultimap(
839 ListMultimap<K, V> multimap) {
840 return Synchronized.listMultimap(multimap, null);
841 }
842
843 /**
844 * Returns an unmodifiable view of the specified {@code ListMultimap}. Query
845 * operations on the returned multimap "read through" to the specified
846 * multimap, and attempts to modify the returned multimap, either directly or
847 * through the multimap's views, result in an
848 * {@code UnsupportedOperationException}.
849 *
850 * <p>Note that the generated multimap's {@link Multimap#removeAll} and
851 * {@link Multimap#replaceValues} methods return collections that are
852 * modifiable.
853 *
854 * <p>The returned multimap will be serializable if the specified multimap is
855 * serializable.
856 *
857 * @param delegate the multimap for which an unmodifiable view is to be
858 * returned
859 * @return an unmodifiable view of the specified multimap
860 */
861 public static <K, V> ListMultimap<K, V> unmodifiableListMultimap(
862 ListMultimap<K, V> delegate) {
863 if (delegate instanceof UnmodifiableListMultimap ||
864 delegate instanceof ImmutableListMultimap) {
865 return delegate;
866 }
867 return new UnmodifiableListMultimap<K, V>(delegate);
868 }
869
870 /**
871 * Simply returns its argument.
872 *
873 * @deprecated no need to use this
874 * @since 10.0
875 */
876 @Deprecated public static <K, V> ListMultimap<K, V> unmodifiableListMultimap(
877 ImmutableListMultimap<K, V> delegate) {
878 return checkNotNull(delegate);
879 }
880
881 /**
882 * Returns an unmodifiable view of the specified collection, preserving the
883 * interface for instances of {@code SortedSet}, {@code Set}, {@code List} and
884 * {@code Collection}, in that order of preference.
885 *
886 * @param collection the collection for which to return an unmodifiable view
887 * @return an unmodifiable view of the collection
888 */
889 private static <V> Collection<V> unmodifiableValueCollection(
890 Collection<V> collection) {
891 if (collection instanceof SortedSet) {
892 return Collections.unmodifiableSortedSet((SortedSet<V>) collection);
893 } else if (collection instanceof Set) {
894 return Collections.unmodifiableSet((Set<V>) collection);
895 } else if (collection instanceof List) {
896 return Collections.unmodifiableList((List<V>) collection);
897 }
898 return Collections.unmodifiableCollection(collection);
899 }
900
901 /**
902 * Returns an unmodifiable view of the specified multimap {@code asMap} entry.
903 * The {@link Entry#setValue} operation throws an {@link
904 * UnsupportedOperationException}, and the collection returned by {@code
905 * getValue} is also an unmodifiable (type-preserving) view. This also has the
906 * side-effect of redefining equals to comply with the Map.Entry contract, and
907 * to avoid a possible nefarious implementation of equals.
908 *
909 * @param entry the entry for which to return an unmodifiable view
910 * @return an unmodifiable view of the entry
911 */
912 private static <K, V> Map.Entry<K, Collection<V>> unmodifiableAsMapEntry(
913 final Map.Entry<K, Collection<V>> entry) {
914 checkNotNull(entry);
915 return new AbstractMapEntry<K, Collection<V>>() {
916 @Override public K getKey() {
917 return entry.getKey();
918 }
919
920 @Override public Collection<V> getValue() {
921 return unmodifiableValueCollection(entry.getValue());
922 }
923 };
924 }
925
926 /**
927 * Returns an unmodifiable view of the specified collection of entries. The
928 * {@link Entry#setValue} operation throws an {@link
929 * UnsupportedOperationException}. If the specified collection is a {@code
930 * Set}, the returned collection is also a {@code Set}.
931 *
932 * @param entries the entries for which to return an unmodifiable view
933 * @return an unmodifiable view of the entries
934 */
935 private static <K, V> Collection<Entry<K, V>> unmodifiableEntries(
936 Collection<Entry<K, V>> entries) {
937 if (entries instanceof Set) {
938 return Maps.unmodifiableEntrySet((Set<Entry<K, V>>) entries);
939 }
940 return new Maps.UnmodifiableEntries<K, V>(
941 Collections.unmodifiableCollection(entries));
942 }
943
944 /**
945 * Returns an unmodifiable view of the specified set of {@code asMap} entries.
946 * The {@link Entry#setValue} operation throws an {@link
947 * UnsupportedOperationException}, as do any operations that attempt to modify
948 * the returned collection.
949 *
950 * @param asMapEntries the {@code asMap} entries for which to return an
951 * unmodifiable view
952 * @return an unmodifiable view of the collection entries
953 */
954 private static <K, V> Set<Entry<K, Collection<V>>> unmodifiableAsMapEntries(
955 Set<Entry<K, Collection<V>>> asMapEntries) {
956 return new UnmodifiableAsMapEntries<K, V>(
957 Collections.unmodifiableSet(asMapEntries));
958 }
959
960 /** @see Multimaps#unmodifiableAsMapEntries */
961 static class UnmodifiableAsMapEntries<K, V>
962 extends ForwardingSet<Entry<K, Collection<V>>> {
963 private final Set<Entry<K, Collection<V>>> delegate;
964 UnmodifiableAsMapEntries(Set<Entry<K, Collection<V>>> delegate) {
965 this.delegate = delegate;
966 }
967
968 @Override protected Set<Entry<K, Collection<V>>> delegate() {
969 return delegate;
970 }
971
972 @Override public Iterator<Entry<K, Collection<V>>> iterator() {
973 final Iterator<Entry<K, Collection<V>>> iterator = delegate.iterator();
974 return new ForwardingIterator<Entry<K, Collection<V>>>() {
975 @Override protected Iterator<Entry<K, Collection<V>>> delegate() {
976 return iterator;
977 }
978 @Override public Entry<K, Collection<V>> next() {
979 return unmodifiableAsMapEntry(iterator.next());
980 }
981 };
982 }
983
984 @Override public Object[] toArray() {
985 return standardToArray();
986 }
987
988 @Override public <T> T[] toArray(T[] array) {
989 return standardToArray(array);
990 }
991
992 @Override public boolean contains(Object o) {
993 return Maps.containsEntryImpl(delegate(), o);
994 }
995
996 @Override public boolean containsAll(Collection<?> c) {
997 return standardContainsAll(c);
998 }
999
1000 @Override public boolean equals(@Nullable Object object) {
1001 return standardEquals(object);
1002 }
1003 }
1004
1005 /**
1006 * Returns a multimap view of the specified map. The multimap is backed by the
1007 * map, so changes to the map are reflected in the multimap, and vice versa.
1008 * If the map is modified while an iteration over one of the multimap's
1009 * collection views is in progress (except through the iterator's own {@code
1010 * remove} operation, or through the {@code setValue} operation on a map entry
1011 * returned by the iterator), the results of the iteration are undefined.
1012 *
1013 * <p>The multimap supports mapping removal, which removes the corresponding
1014 * mapping from the map. It does not support any operations which might add
1015 * mappings, such as {@code put}, {@code putAll} or {@code replaceValues}.
1016 *
1017 * <p>The returned multimap will be serializable if the specified map is
1018 * serializable.
1019 *
1020 * @param map the backing map for the returned multimap view
1021 */
1022 public static <K, V> SetMultimap<K, V> forMap(Map<K, V> map) {
1023 return new MapMultimap<K, V>(map);
1024 }
1025
1026 /** @see Multimaps#forMap */
1027 private static class MapMultimap<K, V>
1028 implements SetMultimap<K, V>, Serializable {
1029 final Map<K, V> map;
1030 transient Map<K, Collection<V>> asMap;
1031
1032 MapMultimap(Map<K, V> map) {
1033 this.map = checkNotNull(map);
1034 }
1035
1036 @Override
1037 public int size() {
1038 return map.size();
1039 }
1040
1041 @Override
1042 public boolean isEmpty() {
1043 return map.isEmpty();
1044 }
1045
1046 @Override
1047 public boolean containsKey(Object key) {
1048 return map.containsKey(key);
1049 }
1050
1051 @Override
1052 public boolean containsValue(Object value) {
1053 return map.containsValue(value);
1054 }
1055
1056 @Override
1057 public boolean containsEntry(Object key, Object value) {
1058 return map.entrySet().contains(Maps.immutableEntry(key, value));
1059 }
1060
1061 @Override
1062 public Set<V> get(final K key) {
1063 return new AbstractSet<V>() {
1064 @Override public Iterator<V> iterator() {
1065 return new Iterator<V>() {
1066 int i;
1067
1068 @Override
1069 public boolean hasNext() {
1070 return (i == 0) && map.containsKey(key);
1071 }
1072
1073 @Override
1074 public V next() {
1075 if (!hasNext()) {
1076 throw new NoSuchElementException();
1077 }
1078 i++;
1079 return map.get(key);
1080 }
1081
1082 @Override
1083 public void remove() {
1084 checkState(i == 1);
1085 i = -1;
1086 map.remove(key);
1087 }
1088 };
1089 }
1090
1091 @Override public int size() {
1092 return map.containsKey(key) ? 1 : 0;
1093 }
1094 };
1095 }
1096
1097 @Override
1098 public boolean put(K key, V value) {
1099 throw new UnsupportedOperationException();
1100 }
1101
1102 @Override
1103 public boolean putAll(K key, Iterable<? extends V> values) {
1104 throw new UnsupportedOperationException();
1105 }
1106
1107 @Override
1108 public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
1109 throw new UnsupportedOperationException();
1110 }
1111
1112 @Override
1113 public Set<V> replaceValues(K key, Iterable<? extends V> values) {
1114 throw new UnsupportedOperationException();
1115 }
1116
1117 @Override
1118 public boolean remove(Object key, Object value) {
1119 return map.entrySet().remove(Maps.immutableEntry(key, value));
1120 }
1121
1122 @Override
1123 public Set<V> removeAll(Object key) {
1124 Set<V> values = new HashSet<V>(2);
1125 if (!map.containsKey(key)) {
1126 return values;
1127 }
1128 values.add(map.remove(key));
1129 return values;
1130 }
1131
1132 @Override
1133 public void clear() {
1134 map.clear();
1135 }
1136
1137 @Override
1138 public Set<K> keySet() {
1139 return map.keySet();
1140 }
1141
1142 @Override
1143 public Multiset<K> keys() {
1144 return Multisets.forSet(map.keySet());
1145 }
1146
1147 @Override
1148 public Collection<V> values() {
1149 return map.values();
1150 }
1151
1152 @Override
1153 public Set<Entry<K, V>> entries() {
1154 return map.entrySet();
1155 }
1156
1157 @Override
1158 public Map<K, Collection<V>> asMap() {
1159 Map<K, Collection<V>> result = asMap;
1160 if (result == null) {
1161 asMap = result = new AsMap();
1162 }
1163 return result;
1164 }
1165
1166 @Override public boolean equals(@Nullable Object object) {
1167 if (object == this) {
1168 return true;
1169 }
1170 if (object instanceof Multimap) {
1171 Multimap<?, ?> that = (Multimap<?, ?>) object;
1172 return this.size() == that.size() && asMap().equals(that.asMap());
1173 }
1174 return false;
1175 }
1176
1177 @Override public int hashCode() {
1178 return map.hashCode();
1179 }
1180
1181 private static final MapJoiner JOINER
1182 = Joiner.on("], ").withKeyValueSeparator("=[").useForNull("null");
1183
1184 @Override public String toString() {
1185 if (map.isEmpty()) {
1186 return "{}";
1187 }
1188 StringBuilder builder
1189 = Collections2.newStringBuilderForCollection(map.size()).append('{');
1190 JOINER.appendTo(builder, map);
1191 return builder.append("]}").toString();
1192 }
1193
1194 /** @see MapMultimap#asMap */
1195 class AsMapEntries extends AbstractSet<Entry<K, Collection<V>>> {
1196 @Override public int size() {
1197 return map.size();
1198 }
1199
1200 @Override public Iterator<Entry<K, Collection<V>>> iterator() {
1201 return new Iterator<Entry<K, Collection<V>>>() {
1202 final Iterator<K> keys = map.keySet().iterator();
1203
1204 @Override
1205 public boolean hasNext() {
1206 return keys.hasNext();
1207 }
1208 @Override
1209 public Entry<K, Collection<V>> next() {
1210 final K key = keys.next();
1211 return new AbstractMapEntry<K, Collection<V>>() {
1212 @Override public K getKey() {
1213 return key;
1214 }
1215 @Override public Collection<V> getValue() {
1216 return get(key);
1217 }
1218 };
1219 }
1220 @Override
1221 public void remove() {
1222 keys.remove();
1223 }
1224 };
1225 }
1226
1227 @Override public boolean contains(Object o) {
1228 if (!(o instanceof Entry)) {
1229 return false;
1230 }
1231 Entry<?, ?> entry = (Entry<?, ?>) o;
1232 if (!(entry.getValue() instanceof Set)) {
1233 return false;
1234 }
1235 Set<?> set = (Set<?>) entry.getValue();
1236 return (set.size() == 1)
1237 && containsEntry(entry.getKey(), set.iterator().next());
1238 }
1239
1240 @Override public boolean remove(Object o) {
1241 if (!(o instanceof Entry)) {
1242 return false;
1243 }
1244 Entry<?, ?> entry = (Entry<?, ?>) o;
1245 if (!(entry.getValue() instanceof Set)) {
1246 return false;
1247 }
1248 Set<?> set = (Set<?>) entry.getValue();
1249 return (set.size() == 1)
1250 && map.entrySet().remove(
1251 Maps.immutableEntry(entry.getKey(), set.iterator().next()));
1252 }
1253 }
1254
1255 /** @see MapMultimap#asMap */
1256 class AsMap extends Maps.ImprovedAbstractMap<K, Collection<V>> {
1257 @Override protected Set<Entry<K, Collection<V>>> createEntrySet() {
1258 return new AsMapEntries();
1259 }
1260
1261 // The following methods are included for performance.
1262
1263 @Override public boolean containsKey(Object key) {
1264 return map.containsKey(key);
1265 }
1266
1267 @SuppressWarnings("unchecked")
1268 @Override public Collection<V> get(Object key) {
1269 Collection<V> collection = MapMultimap.this.get((K) key);
1270 return collection.isEmpty() ? null : collection;
1271 }
1272
1273 @Override public Collection<V> remove(Object key) {
1274 Collection<V> collection = removeAll(key);
1275 return collection.isEmpty() ? null : collection;
1276 }
1277 }
1278 private static final long serialVersionUID = 7845222491160860175L;
1279 }
1280
1281 /**
1282 * Returns a view of a multimap where each value is transformed by a function.
1283 * All other properties of the multimap, such as iteration order, are left
1284 * intact. For example, the code: <pre> {@code
1285 *
1286 * Multimap<String, Integer> multimap =
1287 * ImmutableSetMultimap.of("a", 2, "b", -3, "b", -3, "a", 4, "c", 6);
1288 * Function<Integer, String> square = new Function<Integer, String>() {
1289 * public String apply(Integer in) {
1290 * return Integer.toString(in * in);
1291 * }
1292 * };
1293 * Multimap<String, String> transformed =
1294 * Multimaps.transformValues(multimap, square);
1295 * System.out.println(transformed);}</pre>
1296 *
1297 * ... prints {@code {a=[4, 16], b=[9, 9], c=[6]}}.
1298 *
1299 * <p>Changes in the underlying multimap are reflected in this view.
1300 * Conversely, this view supports removal operations, and these are reflected
1301 * in the underlying multimap.
1302 *
1303 * <p>It's acceptable for the underlying multimap to contain null keys, and
1304 * even null values provided that the function is capable of accepting null
1305 * input. The transformed multimap might contain null values, if the function
1306 * sometimes gives a null result.
1307 *
1308 * <p>The returned multimap is not thread-safe or serializable, even if the
1309 * underlying multimap is. The {@code equals} and {@code hashCode} methods
1310 * of the returned multimap are meaningless, since there is not a definition
1311 * of {@code equals} or {@code hashCode} for general collections, and
1312 * {@code get()} will return a general {@code Collection} as opposed to a
1313 * {@code List} or a {@code Set}.
1314 *
1315 * <p>The function is applied lazily, invoked when needed. This is necessary
1316 * for the returned multimap to be a view, but it means that the function will
1317 * be applied many times for bulk operations like
1318 * {@link Multimap#containsValue} and {@code Multimap.toString()}. For this to
1319 * perform well, {@code function} should be fast. To avoid lazy evaluation
1320 * when the returned multimap doesn't need to be a view, copy the returned
1321 * multimap into a new multimap of your choosing.
1322 *
1323 * @since 7.0
1324 */
1325 @Beta
1326 public static <K, V1, V2> Multimap<K, V2> transformValues(
1327 Multimap<K, V1> fromMultimap, final Function<? super V1, V2> function) {
1328 checkNotNull(function);
1329 EntryTransformer<K, V1, V2> transformer =
1330 new EntryTransformer<K, V1, V2>() {
1331 @Override
1332 public V2 transformEntry(K key, V1 value) {
1333 return function.apply(value);
1334 }
1335 };
1336 return transformEntries(fromMultimap, transformer);
1337 }
1338
1339 /**
1340 * Returns a view of a multimap whose values are derived from the original
1341 * multimap's entries. In contrast to {@link #transformValues}, this method's
1342 * entry-transformation logic may depend on the key as well as the value.
1343 *
1344 * <p>All other properties of the transformed multimap, such as iteration
1345 * order, are left intact. For example, the code: <pre> {@code
1346 *
1347 * SetMultimap<String, Integer> multimap =
1348 * ImmutableSetMultimap.of("a", 1, "a", 4, "b", -6);
1349 * EntryTransformer<String, Integer, String> transformer =
1350 * new EntryTransformer<String, Integer, String>() {
1351 * public String transformEntry(String key, Integer value) {
1352 * return (value >= 0) ? key : "no" + key;
1353 * }
1354 * };
1355 * Multimap<String, String> transformed =
1356 * Multimaps.transformEntries(multimap, transformer);
1357 * System.out.println(transformed);}</pre>
1358 *
1359 * ... prints {@code {a=[a, a], b=[nob]}}.
1360 *
1361 * <p>Changes in the underlying multimap are reflected in this view.
1362 * Conversely, this view supports removal operations, and these are reflected
1363 * in the underlying multimap.
1364 *
1365 * <p>It's acceptable for the underlying multimap to contain null keys and
1366 * null values provided that the transformer is capable of accepting null
1367 * inputs. The transformed multimap might contain null values if the
1368 * transformer sometimes gives a null result.
1369 *
1370 * <p>The returned multimap is not thread-safe or serializable, even if the
1371 * underlying multimap is. The {@code equals} and {@code hashCode} methods
1372 * of the returned multimap are meaningless, since there is not a definition
1373 * of {@code equals} or {@code hashCode} for general collections, and
1374 * {@code get()} will return a general {@code Collection} as opposed to a
1375 * {@code List} or a {@code Set}.
1376 *
1377 * <p>The transformer is applied lazily, invoked when needed. This is
1378 * necessary for the returned multimap to be a view, but it means that the
1379 * transformer will be applied many times for bulk operations like {@link
1380 * Multimap#containsValue} and {@link Object#toString}. For this to perform
1381 * well, {@code transformer} should be fast. To avoid lazy evaluation when the
1382 * returned multimap doesn't need to be a view, copy the returned multimap
1383 * into a new multimap of your choosing.
1384 *
1385 * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
1386 * {@code EntryTransformer} key type {@code K}, {@code k.equals(k2)} implies
1387 * that {@code k2} is also of type {@code K}. Using an {@code
1388 * EntryTransformer} key type for which this may not hold, such as {@code
1389 * ArrayList}, may risk a {@code ClassCastException} when calling methods on
1390 * the transformed multimap.
1391 *
1392 * @since 7.0
1393 */
1394 @Beta
1395 public static <K, V1, V2> Multimap<K, V2> transformEntries(
1396 Multimap<K, V1> fromMap,
1397 EntryTransformer<? super K, ? super V1, V2> transformer) {
1398 return new TransformedEntriesMultimap<K, V1, V2>(fromMap, transformer);
1399 }
1400
1401 private static class TransformedEntriesMultimap<K, V1, V2>
1402 implements Multimap<K, V2> {
1403 final Multimap<K, V1> fromMultimap;
1404 final EntryTransformer<? super K, ? super V1, V2> transformer;
1405
1406 TransformedEntriesMultimap(Multimap<K, V1> fromMultimap,
1407 final EntryTransformer<? super K, ? super V1, V2> transformer) {
1408 this.fromMultimap = checkNotNull(fromMultimap);
1409 this.transformer = checkNotNull(transformer);
1410 }
1411
1412 Collection<V2> transform(final K key, Collection<V1> values) {
1413 return Collections2.transform(values, new Function<V1, V2>() {
1414 @Override public V2 apply(V1 value) {
1415 return transformer.transformEntry(key, value);
1416 }
1417 });
1418 }
1419
1420 private transient Map<K, Collection<V2>> asMap;
1421
1422 @Override public Map<K, Collection<V2>> asMap() {
1423 if (asMap == null) {
1424 Map<K, Collection<V2>> aM = Maps.transformEntries(fromMultimap.asMap(),
1425 new EntryTransformer<K, Collection<V1>, Collection<V2>>() {
1426
1427 @Override public Collection<V2> transformEntry(
1428 K key, Collection<V1> value) {
1429 return transform(key, value);
1430 }
1431 });
1432 asMap = aM;
1433 return aM;
1434 }
1435 return asMap;
1436 }
1437
1438 @Override public void clear() {
1439 fromMultimap.clear();
1440 }
1441
1442 @SuppressWarnings("unchecked")
1443 @Override public boolean containsEntry(Object key, Object value) {
1444 Collection<V2> values = get((K) key);
1445 return values.contains(value);
1446 }
1447
1448 @Override public boolean containsKey(Object key) {
1449 return fromMultimap.containsKey(key);
1450 }
1451
1452 @Override public boolean containsValue(Object value) {
1453 return values().contains(value);
1454 }
1455
1456 private transient Collection<Entry<K, V2>> entries;
1457
1458 @Override public Collection<Entry<K, V2>> entries() {
1459 if (entries == null) {
1460 Collection<Entry<K, V2>> es = new TransformedEntries(transformer);
1461 entries = es;
1462 return es;
1463 }
1464 return entries;
1465 }
1466
1467 private class TransformedEntries
1468 extends TransformedCollection<Entry<K, V1>, Entry<K, V2>> {
1469
1470 TransformedEntries(
1471 final EntryTransformer<? super K, ? super V1, V2> transformer) {
1472 super(fromMultimap.entries(),
1473 new Function<Entry<K, V1>, Entry<K, V2>>() {
1474 @Override public Entry<K, V2> apply(final Entry<K, V1> entry) {
1475 return new AbstractMapEntry<K, V2>() {
1476
1477 @Override public K getKey() {
1478 return entry.getKey();
1479 }
1480
1481 @Override public V2 getValue() {
1482 return transformer.transformEntry(
1483 entry.getKey(), entry.getValue());
1484 }
1485 };
1486 }
1487 });
1488 }
1489
1490 @Override public boolean contains(Object o) {
1491 if (o instanceof Entry) {
1492 Entry<?, ?> entry = (Entry<?, ?>) o;
1493 return containsEntry(entry.getKey(), entry.getValue());
1494 }
1495 return false;
1496 }
1497
1498 @SuppressWarnings("unchecked")
1499 @Override public boolean remove(Object o) {
1500 if (o instanceof Entry) {
1501 Entry<?, ?> entry = (Entry<?, ?>) o;
1502 Collection<V2> values = get((K) entry.getKey());
1503 return values.remove(entry.getValue());
1504 }
1505 return false;
1506 }
1507
1508 }
1509
1510 @Override public Collection<V2> get(final K key) {
1511 return transform(key, fromMultimap.get(key));
1512 }
1513
1514 @Override public boolean isEmpty() {
1515 return fromMultimap.isEmpty();
1516 }
1517
1518 @Override public Set<K> keySet() {
1519 return fromMultimap.keySet();
1520 }
1521
1522 @Override public Multiset<K> keys() {
1523 return fromMultimap.keys();
1524 }
1525
1526 @Override public boolean put(K key, V2 value) {
1527 throw new UnsupportedOperationException();
1528 }
1529
1530 @Override public boolean putAll(K key, Iterable<? extends V2> values) {
1531 throw new UnsupportedOperationException();
1532 }
1533
1534 @Override public boolean putAll(
1535 Multimap<? extends K, ? extends V2> multimap) {
1536 throw new UnsupportedOperationException();
1537 }
1538
1539 @SuppressWarnings("unchecked")
1540 @Override public boolean remove(Object key, Object value) {
1541 return get((K) key).remove(value);
1542 }
1543
1544 @SuppressWarnings("unchecked")
1545 @Override public Collection<V2> removeAll(Object key) {
1546 return transform((K) key, fromMultimap.removeAll(key));
1547 }
1548
1549 @Override public Collection<V2> replaceValues(
1550 K key, Iterable<? extends V2> values) {
1551 throw new UnsupportedOperationException();
1552 }
1553
1554 @Override public int size() {
1555 return fromMultimap.size();
1556 }
1557
1558 private transient Collection<V2> values;
1559
1560 @Override public Collection<V2> values() {
1561 if (values == null) {
1562 Collection<V2> vs = Collections2.transform(
1563 fromMultimap.entries(), new Function<Entry<K, V1>, V2>() {
1564
1565 @Override public V2 apply(Entry<K, V1> entry) {
1566 return transformer.transformEntry(
1567 entry.getKey(), entry.getValue());
1568 }
1569 });
1570 values = vs;
1571 return vs;
1572 }
1573 return values;
1574 }
1575
1576 @Override public boolean equals(Object obj) {
1577 if (obj instanceof Multimap) {
1578 Multimap<?, ?> other = (Multimap<?, ?>) obj;
1579 return asMap().equals(other.asMap());
1580 }
1581 return false;
1582 }
1583
1584 @Override public int hashCode() {
1585 return asMap().hashCode();
1586 }
1587
1588 @Override public String toString() {
1589 return asMap().toString();
1590 }
1591 }
1592
1593 /**
1594 * Returns a view of a {@code ListMultimap} where each value is transformed by
1595 * a function. All other properties of the multimap, such as iteration order,
1596 * are left intact. For example, the code: <pre> {@code
1597 *
1598 * ListMultimap<String, Integer> multimap
1599 * = ImmutableListMultimap.of("a", 4, "a", 16, "b", 9);
1600 * Function<Integer, Double> sqrt =
1601 * new Function<Integer, Double>() {
1602 * public Double apply(Integer in) {
1603 * return Math.sqrt((int) in);
1604 * }
1605 * };
1606 * ListMultimap<String, Double> transformed = Multimaps.transformValues(map,
1607 * sqrt);
1608 * System.out.println(transformed);}</pre>
1609 *
1610 * ... prints {@code {a=[2.0, 4.0], b=[3.0]}}.
1611 *
1612 * <p>Changes in the underlying multimap are reflected in this view.
1613 * Conversely, this view supports removal operations, and these are reflected
1614 * in the underlying multimap.
1615 *
1616 * <p>It's acceptable for the underlying multimap to contain null keys, and
1617 * even null values provided that the function is capable of accepting null
1618 * input. The transformed multimap might contain null values, if the function
1619 * sometimes gives a null result.
1620 *
1621 * <p>The returned multimap is not thread-safe or serializable, even if the
1622 * underlying multimap is.
1623 *
1624 * <p>The function is applied lazily, invoked when needed. This is necessary
1625 * for the returned multimap to be a view, but it means that the function will
1626 * be applied many times for bulk operations like
1627 * {@link Multimap#containsValue} and {@code Multimap.toString()}. For this to
1628 * perform well, {@code function} should be fast. To avoid lazy evaluation
1629 * when the returned multimap doesn't need to be a view, copy the returned
1630 * multimap into a new multimap of your choosing.
1631 *
1632 * @since 7.0
1633 */
1634 @Beta
1635 public static <K, V1, V2> ListMultimap<K, V2> transformValues(
1636 ListMultimap<K, V1> fromMultimap,
1637 final Function<? super V1, V2> function) {
1638 checkNotNull(function);
1639 EntryTransformer<K, V1, V2> transformer =
1640 new EntryTransformer<K, V1, V2>() {
1641 @Override
1642 public V2 transformEntry(K key, V1 value) {
1643 return function.apply(value);
1644 }
1645 };
1646 return transformEntries(fromMultimap, transformer);
1647 }
1648
1649 /**
1650 * Returns a view of a {@code ListMultimap} whose values are derived from the
1651 * original multimap's entries. In contrast to
1652 * {@link #transformValues(ListMultimap, Function)}, this method's
1653 * entry-transformation logic may depend on the key as well as the value.
1654 *
1655 * <p>All other properties of the transformed multimap, such as iteration
1656 * order, are left intact. For example, the code: <pre> {@code
1657 *
1658 * Multimap<String, Integer> multimap =
1659 * ImmutableMultimap.of("a", 1, "a", 4, "b", 6);
1660 * EntryTransformer<String, Integer, String> transformer =
1661 * new EntryTransformer<String, Integer, String>() {
1662 * public String transformEntry(String key, Integer value) {
1663 * return key + value;
1664 * }
1665 * };
1666 * Multimap<String, String> transformed =
1667 * Multimaps.transformEntries(multimap, transformer);
1668 * System.out.println(transformed);}</pre>
1669 *
1670 * ... prints {@code {"a"=["a1", "a4"], "b"=["b6"]}}.
1671 *
1672 * <p>Changes in the underlying multimap are reflected in this view.
1673 * Conversely, this view supports removal operations, and these are reflected
1674 * in the underlying multimap.
1675 *
1676 * <p>It's acceptable for the underlying multimap to contain null keys and
1677 * null values provided that the transformer is capable of accepting null
1678 * inputs. The transformed multimap might contain null values if the
1679 * transformer sometimes gives a null result.
1680 *
1681 * <p>The returned multimap is not thread-safe or serializable, even if the
1682 * underlying multimap is.
1683 *
1684 * <p>The transformer is applied lazily, invoked when needed. This is
1685 * necessary for the returned multimap to be a view, but it means that the
1686 * transformer will be applied many times for bulk operations like {@link
1687 * Multimap#containsValue} and {@link Object#toString}. For this to perform
1688 * well, {@code transformer} should be fast. To avoid lazy evaluation when the
1689 * returned multimap doesn't need to be a view, copy the returned multimap
1690 * into a new multimap of your choosing.
1691 *
1692 * <p><b>Warning:</b> This method assumes that for any instance {@code k} of
1693 * {@code EntryTransformer} key type {@code K}, {@code k.equals(k2)} implies
1694 * that {@code k2} is also of type {@code K}. Using an {@code
1695 * EntryTransformer} key type for which this may not hold, such as {@code
1696 * ArrayList}, may risk a {@code ClassCastException} when calling methods on
1697 * the transformed multimap.
1698 *
1699 * @since 7.0
1700 */
1701 @Beta
1702 public static <K, V1, V2> ListMultimap<K, V2> transformEntries(
1703 ListMultimap<K, V1> fromMap,
1704 EntryTransformer<? super K, ? super V1, V2> transformer) {
1705 return new TransformedEntriesListMultimap<K, V1, V2>(fromMap, transformer);
1706 }
1707
1708 private static final class TransformedEntriesListMultimap<K, V1, V2>
1709 extends TransformedEntriesMultimap<K, V1, V2>
1710 implements ListMultimap<K, V2> {
1711
1712 TransformedEntriesListMultimap(ListMultimap<K, V1> fromMultimap,
1713 EntryTransformer<? super K, ? super V1, V2> transformer) {
1714 super(fromMultimap, transformer);
1715 }
1716
1717 @Override List<V2> transform(final K key, Collection<V1> values) {
1718 return Lists.transform((List<V1>) values, new Function<V1, V2>() {
1719 @Override public V2 apply(V1 value) {
1720 return transformer.transformEntry(key, value);
1721 }
1722 });
1723 }
1724
1725 @Override public List<V2> get(K key) {
1726 return transform(key, fromMultimap.get(key));
1727 }
1728
1729 @SuppressWarnings("unchecked")
1730 @Override public List<V2> removeAll(Object key) {
1731 return transform((K) key, fromMultimap.removeAll(key));
1732 }
1733
1734 @Override public List<V2> replaceValues(
1735 K key, Iterable<? extends V2> values) {
1736 throw new UnsupportedOperationException();
1737 }
1738 }
1739
1740 /**
1741 * Creates an index {@code ImmutableListMultimap} that contains the results of
1742 * applying a specified function to each item in an {@code Iterable} of
1743 * values. Each value will be stored as a value in the resulting multimap,
1744 * yielding a multimap with the same size as the input iterable. The key used
1745 * to store that value in the multimap will be the result of calling the
1746 * function on that value. The resulting multimap is created as an immutable
1747 * snapshot. In the returned multimap, keys appear in the order they are first
1748 * encountered, and the values corresponding to each key appear in the same
1749 * order as they are encountered.
1750 *
1751 * <p>For example, <pre> {@code
1752 *
1753 * List<String> badGuys =
1754 * Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
1755 * Function<String, Integer> stringLengthFunction = ...;
1756 * Multimap<Integer, String> index =
1757 * Multimaps.index(badGuys, stringLengthFunction);
1758 * System.out.println(index);}</pre>
1759 *
1760 * prints <pre> {@code
1761 *
1762 * {4=[Inky], 6=[Blinky], 5=[Pinky, Pinky, Clyde]}}</pre>
1763 *
1764 * The returned multimap is serializable if its keys and values are all
1765 * serializable.
1766 *
1767 * @param values the values to use when constructing the {@code
1768 * ImmutableListMultimap}
1769 * @param keyFunction the function used to produce the key for each value
1770 * @return {@code ImmutableListMultimap} mapping the result of evaluating the
1771 * function {@code keyFunction} on each value in the input collection to
1772 * that value
1773 * @throws NullPointerException if any of the following cases is true:
1774 * <ul>
1775 * <li>{@code values} is null
1776 * <li>{@code keyFunction} is null
1777 * <li>An element in {@code values} is null
1778 * <li>{@code keyFunction} returns {@code null} for any element of {@code
1779 * values}
1780 * </ul>
1781 */
1782 public static <K, V> ImmutableListMultimap<K, V> index(
1783 Iterable<V> values, Function<? super V, K> keyFunction) {
1784 return index(values.iterator(), keyFunction);
1785 }
1786
1787 /**
1788 * <b>Deprecated.</b>
1789 *
1790 * @since 10.0
1791 * @deprecated use {@link #index(Iterator, Function)} by casting {@code
1792 * values} to {@code Iterator<V>}, or better yet, by implementing only
1793 * {@code Iterator} and not {@code Iterable}. <b>This method is scheduled
1794 * for deletion in March 2012.</b>
1795 */
1796 @Beta
1797 @Deprecated
1798 public static <K, V, I extends Object & Iterable<V> & Iterator<V>>
1799 ImmutableListMultimap<K, V> index(
1800 I values, Function<? super V, K> keyFunction) {
1801 Iterable<V> valuesIterable = checkNotNull(values);
1802 return index(valuesIterable, keyFunction);
1803 }
1804
1805 /**
1806 * Creates an index {@code ImmutableListMultimap} that contains the results of
1807 * applying a specified function to each item in an {@code Iterator} of
1808 * values. Each value will be stored as a value in the resulting multimap,
1809 * yielding a multimap with the same size as the input iterator. The key used
1810 * to store that value in the multimap will be the result of calling the
1811 * function on that value. The resulting multimap is created as an immutable
1812 * snapshot. In the returned multimap, keys appear in the order they are first
1813 * encountered, and the values corresponding to each key appear in the same
1814 * order as they are encountered.
1815 *
1816 * <p>For example, <pre> {@code
1817 *
1818 * List<String> badGuys =
1819 * Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
1820 * Function<String, Integer> stringLengthFunction = ...;
1821 * Multimap<Integer, String> index =
1822 * Multimaps.index(badGuys.iterator(), stringLengthFunction);
1823 * System.out.println(index);}</pre>
1824 *
1825 * prints <pre> {@code
1826 *
1827 * {4=[Inky], 6=[Blinky], 5=[Pinky, Pinky, Clyde]}}</pre>
1828 *
1829 * The returned multimap is serializable if its keys and values are all
1830 * serializable.
1831 *
1832 * @param values the values to use when constructing the {@code
1833 * ImmutableListMultimap}
1834 * @param keyFunction the function used to produce the key for each value
1835 * @return {@code ImmutableListMultimap} mapping the result of evaluating the
1836 * function {@code keyFunction} on each value in the input collection to
1837 * that value
1838 * @throws NullPointerException if any of the following cases is true:
1839 * <ul>
1840 * <li>{@code values} is null
1841 * <li>{@code keyFunction} is null
1842 * <li>An element in {@code values} is null
1843 * <li>{@code keyFunction} returns {@code null} for any element of {@code
1844 * values}
1845 * </ul>
1846 * @since 10.0
1847 */
1848 public static <K, V> ImmutableListMultimap<K, V> index(
1849 Iterator<V> values, Function<? super V, K> keyFunction) {
1850 checkNotNull(keyFunction);
1851 ImmutableListMultimap.Builder<K, V> builder
1852 = ImmutableListMultimap.builder();
1853 while (values.hasNext()) {
1854 V value = values.next();
1855 checkNotNull(value, values);
1856 builder.put(keyFunction.apply(value), value);
1857 }
1858 return builder.build();
1859 }
1860
1861 static abstract class Keys<K, V> extends AbstractMultiset<K> {
1862 abstract Multimap<K, V> multimap();
1863
1864 @Override Iterator<Multiset.Entry<K>> entryIterator() {
1865 final Iterator<Map.Entry<K, Collection<V>>> backingIterator =
1866 multimap().asMap().entrySet().iterator();
1867 return new Iterator<Multiset.Entry<K>>() {
1868 @Override public boolean hasNext() {
1869 return backingIterator.hasNext();
1870 }
1871
1872 @Override public Multiset.Entry<K> next() {
1873 final Map.Entry<K, Collection<V>> backingEntry =
1874 backingIterator.next();
1875 return new Multisets.AbstractEntry<K>() {
1876 @Override public K getElement() {
1877 return backingEntry.getKey();
1878 }
1879
1880 @Override public int getCount() {
1881 return backingEntry.getValue().size();
1882 }
1883 };
1884 }
1885
1886 @Override public void remove() {
1887 backingIterator.remove();
1888 }
1889 };
1890 }
1891
1892 @Override int distinctElements() {
1893 return multimap().asMap().size();
1894 }
1895
1896 @Override Set<Multiset.Entry<K>> createEntrySet() {
1897 return new KeysEntrySet();
1898 }
1899
1900 class KeysEntrySet extends Multisets.EntrySet<K> {
1901 @Override Multiset<K> multiset() {
1902 return Keys.this;
1903 }
1904
1905 @Override public Iterator<Multiset.Entry<K>> iterator() {
1906 return entryIterator();
1907 }
1908
1909 @Override public int size() {
1910 return distinctElements();
1911 }
1912
1913 @Override public boolean isEmpty() {
1914 return multimap().isEmpty();
1915 }
1916
1917 @Override public boolean contains(@Nullable Object o) {
1918 if (o instanceof Multiset.Entry<?>) {
1919 Multiset.Entry<?> entry = (Multiset.Entry<?>) o;
1920 Collection<V> collection = multimap().asMap().get(entry.getElement());
1921 return collection != null && collection.size() == entry.getCount();
1922 }
1923 return false;
1924 }
1925
1926 @Override public boolean remove(@Nullable Object o) {
1927 if (o instanceof Multiset.Entry<?>) {
1928 Multiset.Entry<?> entry = (Multiset.Entry<?>) o;
1929 Collection<V> collection = multimap().asMap().get(entry.getElement());
1930 if (collection != null && collection.size() == entry.getCount()) {
1931 collection.clear();
1932 return true;
1933 }
1934 }
1935 return false;
1936 }
1937 }
1938
1939 @Override public boolean contains(@Nullable Object element) {
1940 return multimap().containsKey(element);
1941 }
1942
1943 @Override public Iterator<K> iterator() {
1944 return Iterators.transform(multimap().entries().iterator(),
1945 new Function<Map.Entry<K, V>, K>() {
1946 @Override public K apply(Map.Entry<K, V> entry) {
1947 return entry.getKey();
1948 }
1949 });
1950 }
1951
1952 @Override public int count(@Nullable Object element) {
1953 try {
1954 if (multimap().containsKey(element)) {
1955 Collection<V> values = multimap().asMap().get(element);
1956 return (values == null) ? 0 : values.size();
1957 }
1958 return 0;
1959 } catch (ClassCastException e) {
1960 return 0;
1961 } catch (NullPointerException e) {
1962 return 0;
1963 }
1964 }
1965
1966 @Override public int remove(@Nullable Object element, int occurrences) {
1967 checkArgument(occurrences >= 0);
1968 if (occurrences == 0) {
1969 return count(element);
1970 }
1971
1972 Collection<V> values;
1973 try {
1974 values = multimap().asMap().get(element);
1975 } catch (ClassCastException e) {
1976 return 0;
1977 } catch (NullPointerException e) {
1978 return 0;
1979 }
1980
1981 if (values == null) {
1982 return 0;
1983 }
1984
1985 int oldCount = values.size();
1986 if (occurrences >= oldCount) {
1987 values.clear();
1988 } else {
1989 Iterator<V> iterator = values.iterator();
1990 for (int i = 0; i < occurrences; i++) {
1991 iterator.next();
1992 iterator.remove();
1993 }
1994 }
1995 return oldCount;
1996 }
1997
1998 @Override public void clear() {
1999 multimap().clear();
2000 }
2001
2002 @Override public Set<K> elementSet() {
2003 return multimap().keySet();
2004 }
2005 }
2006
2007 static abstract class Values<K, V> extends AbstractCollection<V> {
2008 abstract Multimap<K, V> multimap();
2009
2010 @Override public Iterator<V> iterator() {
2011 final Iterator<Map.Entry<K, V>> backingIterator =
2012 multimap().entries().iterator();
2013 return new Iterator<V>() {
2014 @Override public boolean hasNext() {
2015 return backingIterator.hasNext();
2016 }
2017
2018 @Override public V next() {
2019 return backingIterator.next().getValue();
2020 }
2021
2022 @Override public void remove() {
2023 backingIterator.remove();
2024 }
2025 };
2026 }
2027
2028 @Override public int size() {
2029 return multimap().size();
2030 }
2031
2032 @Override public boolean contains(@Nullable Object o) {
2033 return multimap().containsValue(o);
2034 }
2035
2036 @Override public void clear() {
2037 multimap().clear();
2038 }
2039 }
2040
2041 /**
2042 * A skeleton implementation of {@link Multimap#entries()}.
2043 */
2044 static abstract class Entries<K, V> extends
2045 AbstractCollection<Map.Entry<K, V>> {
2046 abstract Multimap<K, V> multimap();
2047
2048 @Override public int size() {
2049 return multimap().size();
2050 }
2051
2052 @Override public boolean contains(@Nullable Object o) {
2053 if (o instanceof Map.Entry<?, ?>) {
2054 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
2055 return multimap().containsEntry(entry.getKey(), entry.getValue());
2056 }
2057 return false;
2058 }
2059
2060 @Override public boolean remove(@Nullable Object o) {
2061 if (o instanceof Map.Entry<?, ?>) {
2062 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
2063 return multimap().remove(entry.getKey(), entry.getValue());
2064 }
2065 return false;
2066 }
2067
2068 @Override public void clear() {
2069 multimap().clear();
2070 }
2071 }
2072
2073 /**
2074 * A skeleton implementation of {@link SetMultimap#entries()}.
2075 */
2076 static abstract class EntrySet<K, V> extends Entries<K, V> implements
2077 Set<Map.Entry<K, V>> {
2078 @Override public int hashCode() {
2079 return Sets.hashCodeImpl(this);
2080 }
2081
2082 @Override public boolean equals(@Nullable Object obj) {
2083 return Sets.equalsImpl(this, obj);
2084 }
2085 }
2086
2087 /**
2088 * A skeleton implementation of {@link Multimap#asMap()}.
2089 */
2090 static abstract class AsMap<K, V> extends
2091 Maps.ImprovedAbstractMap<K, Collection<V>> {
2092 abstract Multimap<K, V> multimap();
2093
2094 @Override public abstract int size();
2095
2096 abstract Iterator<Entry<K, Collection<V>>> entryIterator();
2097
2098 @Override protected Set<Entry<K, Collection<V>>> createEntrySet() {
2099 return new EntrySet();
2100 }
2101
2102 void removeValuesForKey(Object key){
2103 multimap().removeAll(key);
2104 }
2105
2106 class EntrySet extends Maps.EntrySet<K, Collection<V>> {
2107 @Override Map<K, Collection<V>> map() {
2108 return AsMap.this;
2109 }
2110
2111 @Override public Iterator<Entry<K, Collection<V>>> iterator() {
2112 return entryIterator();
2113 }
2114
2115 @Override public boolean remove(Object o) {
2116 if (!contains(o)) {
2117 return false;
2118 }
2119 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
2120 removeValuesForKey(entry.getKey());
2121 return true;
2122 }
2123 }
2124
2125 @SuppressWarnings("unchecked")
2126 @Override public Collection<V> get(Object key) {
2127 return containsKey(key) ? multimap().get((K) key) : null;
2128 }
2129
2130 @Override public Collection<V> remove(Object key) {
2131 return containsKey(key) ? multimap().removeAll(key) : null;
2132 }
2133
2134 @Override public Set<K> keySet() {
2135 return multimap().keySet();
2136 }
2137
2138 @Override public boolean isEmpty() {
2139 return multimap().isEmpty();
2140 }
2141
2142 @Override public boolean containsKey(Object key) {
2143 return multimap().containsKey(key);
2144 }
2145
2146 @Override public void clear() {
2147 multimap().clear();
2148 }
2149 }
2150
2151 /**
2152 * Returns a multimap containing the mappings in {@code unfiltered} whose keys
2153 * satisfy a predicate. The returned multimap is a live view of
2154 * {@code unfiltered}; changes to one affect the other.
2155 *
2156 * <p>The resulting multimap's views have iterators that don't support
2157 * {@code remove()}, but all other methods are supported by the multimap and
2158 * its views. When adding a key that doesn't satisfy the predicate, the
2159 * multimap's {@code put()}, {@code putAll()}, and {@replaceValues()} methods
2160 * throw an {@link IllegalArgumentException}.
2161 *
2162 * <p>When methods such as {@code removeAll()} and {@code clear()} are called on
2163 * the filtered multimap or its views, only mappings whose keys satisfy the
2164 * filter will be removed from the underlying multimap.
2165 *
2166 * <p>The returned multimap isn't threadsafe or serializable, even if
2167 * {@code unfiltered} is.
2168 *
2169 * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate
2170 * across every key/value mapping in the underlying multimap and determine
2171 * which satisfy the filter. When a live view is <i>not</i> needed, it may be
2172 * faster to copy the filtered multimap and use the copy.
2173 *
2174 * <p><b>Warning:</b> {@code keyPredicate} must be <i>consistent with equals</i>,
2175 * as documented at {@link Predicate#apply}. Do not provide a predicate such
2176 * as {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent
2177 * with equals.
2178 *
2179 * @since 11.0
2180 */
2181 @Beta
2182 @GwtIncompatible(value = "untested")
2183 public static <K, V> Multimap<K, V> filterKeys(
2184 Multimap<K, V> unfiltered, final Predicate<? super K> keyPredicate) {
2185 checkNotNull(keyPredicate);
2186 Predicate<Entry<K, V>> entryPredicate =
2187 new Predicate<Entry<K, V>>() {
2188 @Override
2189 public boolean apply(Entry<K, V> input) {
2190 return keyPredicate.apply(input.getKey());
2191 }
2192 };
2193 return filterEntries(unfiltered, entryPredicate);
2194 }
2195
2196 /**
2197 * Returns a multimap containing the mappings in {@code unfiltered} whose values
2198 * satisfy a predicate. The returned multimap is a live view of
2199 * {@code unfiltered}; changes to one affect the other.
2200 *
2201 * <p>The resulting multimap's views have iterators that don't support
2202 * {@code remove()}, but all other methods are supported by the multimap and
2203 * its views. When adding a value that doesn't satisfy the predicate, the
2204 * multimap's {@code put()}, {@code putAll()}, and {@replaceValues()} methods
2205 * throw an {@link IllegalArgumentException}.
2206 *
2207 * <p>When methods such as {@code removeAll()} and {@code clear()} are called on
2208 * the filtered multimap or its views, only mappings whose value satisfy the
2209 * filter will be removed from the underlying multimap.
2210 *
2211 * <p>The returned multimap isn't threadsafe or serializable, even if
2212 * {@code unfiltered} is.
2213 *
2214 * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate
2215 * across every key/value mapping in the underlying multimap and determine
2216 * which satisfy the filter. When a live view is <i>not</i> needed, it may be
2217 * faster to copy the filtered multimap and use the copy.
2218 *
2219 * <p><b>Warning:</b> {@code valuePredicate} must be <i>consistent with
2220 * equals</i>, as documented at {@link Predicate#apply}. Do not provide a
2221 * predicate such as {@code Predicates.instanceOf(ArrayList.class)}, which is
2222 * inconsistent with equals.
2223 *
2224 * @since 11.0
2225 */
2226 @Beta
2227 @GwtIncompatible(value = "untested")
2228 public static <K, V> Multimap<K, V> filterValues(
2229 Multimap<K, V> unfiltered, final Predicate<? super V> valuePredicate) {
2230 checkNotNull(valuePredicate);
2231 Predicate<Entry<K, V>> entryPredicate =
2232 new Predicate<Entry<K, V>>() {
2233 @Override
2234 public boolean apply(Entry<K, V> input) {
2235 return valuePredicate.apply(input.getValue());
2236 }
2237 };
2238 return filterEntries(unfiltered, entryPredicate);
2239 }
2240
2241 /**
2242 * Returns a multimap containing the mappings in {@code unfiltered} that
2243 * satisfy a predicate. The returned multimap is a live view of
2244 * {@code unfiltered}; changes to one affect the other.
2245 *
2246 * <p>The resulting multimap's views have iterators that don't support
2247 * {@code remove()}, but all other methods are supported by the multimap and
2248 * its views. When adding a key/value pair that doesn't satisfy the predicate,
2249 * multimap's {@code put()}, {@code putAll()}, and {@replaceValues()} methods
2250 * throw an {@link IllegalArgumentException}.
2251 *
2252 * <p>When methods such as {@code removeAll()} and {@code clear()} are called on
2253 * the filtered multimap or its views, only mappings whose keys satisfy the
2254 * filter will be removed from the underlying multimap.
2255 *
2256 * <p>The returned multimap isn't threadsafe or serializable, even if
2257 * {@code unfiltered} is.
2258 *
2259 * <p>Many of the filtered multimap's methods, such as {@code size()}, iterate
2260 * across every key/value mapping in the underlying multimap and determine
2261 * which satisfy the filter. When a live view is <i>not</i> needed, it may be
2262 * faster to copy the filtered multimap and use the copy.
2263 *
2264 * <p><b>Warning:</b> {@code entryPredicate} must be <i>consistent with
2265 * equals</i>, as documented at {@link Predicate#apply}.
2266 *
2267 * @since 11.0
2268 */
2269 @Beta
2270 @GwtIncompatible(value = "untested")
2271 public static <K, V> Multimap<K, V> filterEntries(
2272 Multimap<K, V> unfiltered, Predicate<? super Entry<K, V>> entryPredicate) {
2273 checkNotNull(entryPredicate);
2274 return (unfiltered instanceof FilteredMultimap)
2275 ? filterFiltered((FilteredMultimap<K, V>) unfiltered, entryPredicate)
2276 : new FilteredMultimap<K, V>(checkNotNull(unfiltered), entryPredicate);
2277 }
2278
2279 /**
2280 * Support removal operations when filtering a filtered multimap. Since a
2281 * filtered multimap has iterators that don't support remove, passing one to
2282 * the FilteredMultimap constructor would lead to a multimap whose removal
2283 * operations would fail. This method combines the predicates to avoid that
2284 * problem.
2285 */
2286 private static <K, V> Multimap<K, V> filterFiltered(FilteredMultimap<K, V> map,
2287 Predicate<? super Entry<K, V>> entryPredicate) {
2288 Predicate<Entry<K, V>> predicate
2289 = Predicates.and(map.predicate, entryPredicate);
2290 return new FilteredMultimap<K, V>(map.unfiltered, predicate);
2291 }
2292
2293 private static class FilteredMultimap<K, V> implements Multimap<K, V> {
2294 final Multimap<K, V> unfiltered;
2295 final Predicate<? super Entry<K, V>> predicate;
2296
2297 FilteredMultimap(Multimap<K, V> unfiltered, Predicate<? super Entry<K, V>> predicate) {
2298 this.unfiltered = unfiltered;
2299 this.predicate = predicate;
2300 }
2301
2302 @Override public int size() {
2303 return entries().size();
2304 }
2305
2306 @Override public boolean isEmpty() {
2307 return entries().isEmpty();
2308 }
2309
2310 @Override public boolean containsKey(Object key) {
2311 return asMap().containsKey(key);
2312 }
2313
2314 @Override public boolean containsValue(Object value) {
2315 return values().contains(value);
2316 }
2317
2318 // This method should be called only when key is a K and value is a V.
2319 @SuppressWarnings("unchecked")
2320 boolean satisfiesPredicate(Object key, Object value) {
2321 return predicate.apply(Maps.immutableEntry((K) key, (V) value));
2322 }
2323
2324 @Override public boolean containsEntry(Object key, Object value) {
2325 return unfiltered.containsEntry(key, value) && satisfiesPredicate(key, value);
2326 }
2327
2328 @Override public boolean put(K key, V value) {
2329 checkArgument(satisfiesPredicate(key, value));
2330 return unfiltered.put(key, value);
2331 }
2332
2333 @Override public boolean remove(Object key, Object value) {
2334 return containsEntry(key, value) ? unfiltered.remove(key, value) : false;
2335 }
2336
2337 @Override public boolean putAll(K key, Iterable<? extends V> values) {
2338 for (V value : values) {
2339 checkArgument(satisfiesPredicate(key, value));
2340 }
2341 return unfiltered.putAll(key, values);
2342 }
2343
2344 @Override public boolean putAll(Multimap<? extends K, ? extends V> multimap) {
2345 for (Entry<? extends K, ? extends V> entry : multimap.entries()) {
2346 checkArgument(satisfiesPredicate(entry.getKey(), entry.getValue()));
2347 }
2348 return unfiltered.putAll(multimap);
2349 }
2350
2351 @Override public Collection<V> replaceValues(K key, Iterable<? extends V> values) {
2352 for (V value : values) {
2353 checkArgument(satisfiesPredicate(key, value));
2354 }
2355 // Not calling unfiltered.replaceValues() since values that don't satisify
2356 // the filter should remain in the multimap.
2357 Collection<V> oldValues = removeAll(key);
2358 unfiltered.putAll(key, values);
2359 return oldValues;
2360 }
2361
2362 @Override public Collection<V> removeAll(Object key) {
2363 List<V> removed = Lists.newArrayList();
2364 Collection<V> values = unfiltered.asMap().get(key);
2365 if (values != null) {
2366 Iterator<V> iterator = values.iterator();
2367 while (iterator.hasNext()) {
2368 V value = iterator.next();
2369 if (satisfiesPredicate(key, value)) {
2370 removed.add(value);
2371 iterator.remove();
2372 }
2373 }
2374 }
2375 if (unfiltered instanceof SetMultimap) {
2376 return Collections.unmodifiableSet(Sets.newLinkedHashSet(removed));
2377 } else {
2378 return Collections.unmodifiableList(removed);
2379 }
2380 }
2381
2382 @Override public void clear() {
2383 entries().clear();
2384 }
2385
2386 @Override public boolean equals(@Nullable Object object) {
2387 if (object == this) {
2388 return true;
2389 }
2390 if (object instanceof Multimap) {
2391 Multimap<?, ?> that = (Multimap<?, ?>) object;
2392 return asMap().equals(that.asMap());
2393 }
2394 return false;
2395 }
2396
2397 @Override public int hashCode() {
2398 return asMap().hashCode();
2399 }
2400
2401 @Override public String toString() {
2402 return asMap().toString();
2403 }
2404
2405 class ValuePredicate implements Predicate<V> {
2406 final K key;
2407 ValuePredicate(K key) {
2408 this.key = key;
2409 }
2410 @Override public boolean apply(V value) {
2411 return satisfiesPredicate(key, value);
2412 }
2413 }
2414
2415 Collection<V> filterCollection(Collection<V> collection, Predicate<V> predicate) {
2416 if (collection instanceof Set) {
2417 return Sets.filter((Set<V>) collection, predicate);
2418 } else {
2419 return Collections2.filter(collection, predicate);
2420 }
2421 }
2422
2423 @Override public Collection<V> get(K key) {
2424 return filterCollection(unfiltered.get(key), new ValuePredicate(key));
2425 }
2426
2427 @Override public Set<K> keySet() {
2428 return asMap().keySet();
2429 }
2430
2431 Collection<V> values;
2432
2433 @Override public Collection<V> values() {
2434 return (values == null) ? values = new Values() : values;
2435 }
2436
2437 class Values extends Multimaps.Values<K, V> {
2438 @Override Multimap<K, V> multimap() {
2439 return FilteredMultimap.this;
2440 }
2441
2442 @Override public boolean contains(@Nullable Object o) {
2443 return Iterators.contains(iterator(), o);
2444 }
2445
2446 // Override remove methods since iterator doesn't support remove.
2447
2448 @Override public boolean remove(Object o) {
2449 Iterator<Entry<K, V>> iterator = unfiltered.entries().iterator();
2450 while (iterator.hasNext()) {
2451 Entry<K, V> entry = iterator.next();
2452 if (Objects.equal(o, entry.getValue()) && predicate.apply(entry)) {
2453 iterator.remove();
2454 return true;
2455 }
2456 }
2457 return false;
2458 }
2459
2460 @Override public boolean removeAll(Collection<?> c) {
2461 boolean changed = false;
2462 Iterator<Entry<K, V>> iterator = unfiltered.entries().iterator();
2463 while (iterator.hasNext()) {
2464 Entry<K, V> entry = iterator.next();
2465 if (c.contains(entry.getValue()) && predicate.apply(entry)) {
2466 iterator.remove();
2467 changed = true;
2468 }
2469 }
2470 return changed;
2471 }
2472
2473 @Override public boolean retainAll(Collection<?> c) {
2474 boolean changed = false;
2475 Iterator<Entry<K, V>> iterator = unfiltered.entries().iterator();
2476 while (iterator.hasNext()) {
2477 Entry<K, V> entry = iterator.next();
2478 if (!c.contains(entry.getValue()) && predicate.apply(entry)) {
2479 iterator.remove();
2480 changed = true;
2481 }
2482 }
2483 return changed;
2484 }
2485 }
2486
2487 Collection<Entry<K, V>> entries;
2488
2489 @Override public Collection<Entry<K, V>> entries() {
2490 return (entries == null)
2491 ? entries = Collections2.filter(unfiltered.entries(), predicate)
2492 : entries;
2493 }
2494
2495 /**
2496 * Remove all filtered asMap() entries that satisfy the predicate.
2497 */
2498 boolean removeEntriesIf(Predicate<Map.Entry<K, Collection<V>>> removalPredicate) {
2499 Iterator<Map.Entry<K, Collection<V>>> iterator = unfiltered.asMap().entrySet().iterator();
2500 boolean changed = false;
2501 while (iterator.hasNext()) {
2502 // Determine whether to remove the filtered values with this key.
2503 Map.Entry<K, Collection<V>> entry = iterator.next();
2504 K key = entry.getKey();
2505 Collection<V> collection = entry.getValue();
2506 Predicate<V> valuePredicate = new ValuePredicate(key);
2507 Collection<V> filteredCollection = filterCollection(collection, valuePredicate);
2508 Map.Entry<K, Collection<V>> filteredEntry = Maps.immutableEntry(key, filteredCollection);
2509 if (removalPredicate.apply(filteredEntry) && !filteredCollection.isEmpty()) {
2510 changed = true;
2511 if (Iterables.all(collection, valuePredicate)) {
2512 iterator.remove(); // Remove all values for the key.
2513 } else {
2514 filteredCollection.clear(); // Remove the filtered values only.
2515 }
2516 }
2517 }
2518 return changed;
2519 }
2520
2521 Map<K, Collection<V>> asMap;
2522
2523 @Override public Map<K, Collection<V>> asMap() {
2524 return (asMap == null) ? asMap = createAsMap() : asMap;
2525 }
2526
2527 static final Predicate<Collection<?>> NOT_EMPTY = new Predicate<Collection<?>>() {
2528 @Override public boolean apply(Collection<?> input) {
2529 return !input.isEmpty();
2530 }
2531 };
2532
2533 Map<K, Collection<V>> createAsMap() {
2534 // Select the values that satisify the predicate.
2535 EntryTransformer<K, Collection<V>, Collection<V>> transformer
2536 = new EntryTransformer<K, Collection<V>, Collection<V>>() {
2537 @Override public Collection<V> transformEntry(K key, Collection<V> collection) {
2538 return filterCollection(collection, new ValuePredicate(key));
2539 }
2540 };
2541 Map<K, Collection<V>> transformed
2542 = Maps.transformEntries(unfiltered.asMap(), transformer);
2543
2544 // Select the keys that have at least one value remaining.
2545 Map<K, Collection<V>> filtered = Maps.filterValues(transformed, NOT_EMPTY);
2546
2547 // Override the removal methods, since removing a map entry should not
2548 // affect values that don't satisfy the filter.
2549 return new AsMap(filtered);
2550 }
2551
2552 class AsMap extends ForwardingMap<K, Collection<V>> {
2553 final Map<K, Collection<V>> delegate;
2554
2555 AsMap(Map<K, Collection<V>> delegate) {
2556 this.delegate = delegate;
2557 }
2558
2559 @Override protected Map<K, Collection<V>> delegate() {
2560 return delegate;
2561 }
2562
2563 @Override public Collection<V> remove(Object o) {
2564 Collection<V> output = FilteredMultimap.this.removeAll(o);
2565 return output.isEmpty() ? null : output;
2566 }
2567
2568 @Override public void clear() {
2569 FilteredMultimap.this.clear();
2570 }
2571
2572 Set<K> keySet;
2573
2574 @Override public Set<K> keySet() {
2575 return (keySet == null) ? keySet = new KeySet() : keySet;
2576 }
2577
2578 class KeySet extends Maps.KeySet<K, Collection<V>> {
2579 @Override Map<K, Collection<V>> map() {
2580 return AsMap.this;
2581 }
2582
2583 @Override public boolean remove(Object o) {
2584 Collection<V> collection = delegate.get(o);
2585 if (collection == null) {
2586 return false;
2587 }
2588 collection.clear();
2589 return true;
2590 }
2591
2592 @Override public boolean removeAll(Collection<?> c) {
2593 return Sets.removeAllImpl(this, c);
2594 }
2595
2596 @Override public boolean retainAll(final Collection<?> c) {
2597 Predicate<Map.Entry<K, Collection<V>>> removalPredicate
2598 = new Predicate<Map.Entry<K, Collection<V>>>() {
2599 @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
2600 return !c.contains(entry.getKey());
2601 }
2602 };
2603 return removeEntriesIf(removalPredicate);
2604 }
2605 }
2606
2607 Values asMapValues;
2608
2609 @Override public Collection<Collection<V>> values() {
2610 return (asMapValues == null) ? asMapValues = new Values() : asMapValues;
2611 }
2612
2613 class Values extends Maps.Values<K, Collection<V>> {
2614 @Override Map<K, Collection<V>> map() {
2615 return AsMap.this;
2616 }
2617
2618 @Override public boolean remove(Object o) {
2619 for (Collection<V> collection : this) {
2620 if (collection.equals(o)) {
2621 collection.clear();
2622 return true;
2623 }
2624 }
2625 return false;
2626 }
2627
2628 @Override public boolean removeAll(final Collection<?> c) {
2629 Predicate<Map.Entry<K, Collection<V>>> removalPredicate
2630 = new Predicate<Map.Entry<K, Collection<V>>>() {
2631 @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
2632 return c.contains(entry.getValue());
2633 }
2634 };
2635 return removeEntriesIf(removalPredicate);
2636 }
2637
2638 @Override public boolean retainAll(final Collection<?> c) {
2639 Predicate<Map.Entry<K, Collection<V>>> removalPredicate
2640 = new Predicate<Map.Entry<K, Collection<V>>>() {
2641 @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
2642 return !c.contains(entry.getValue());
2643 }
2644 };
2645 return removeEntriesIf(removalPredicate);
2646 }
2647 }
2648
2649 EntrySet entrySet;
2650
2651 @Override public Set<Map.Entry<K, Collection<V>>> entrySet() {
2652 return (entrySet == null) ? entrySet = new EntrySet(super.entrySet()) : entrySet;
2653 }
2654
2655 class EntrySet extends Maps.EntrySet<K, Collection<V>> {
2656 Set<Map.Entry<K, Collection<V>>> delegateEntries;
2657
2658 public EntrySet(Set<Map.Entry<K, Collection<V>>> delegateEntries) {
2659 this.delegateEntries = delegateEntries;
2660 }
2661
2662 @Override Map<K, Collection<V>> map() {
2663 return AsMap.this;
2664 }
2665
2666 @Override public Iterator<Map.Entry<K, Collection<V>>> iterator() {
2667 return delegateEntries.iterator();
2668 }
2669
2670 @Override public boolean remove(Object o) {
2671 if (o instanceof Entry<?, ?>) {
2672 Entry<?, ?> entry = (Entry<?, ?>) o;
2673 Collection<V> collection = delegate.get(entry.getKey());
2674 if (collection != null && collection.equals(entry.getValue())) {
2675 collection.clear();
2676 return true;
2677 }
2678 }
2679 return false;
2680 }
2681
2682 @Override public boolean removeAll(Collection<?> c) {
2683 return Sets.removeAllImpl(this, c);
2684 }
2685
2686 @Override public boolean retainAll(final Collection<?> c) {
2687 Predicate<Map.Entry<K, Collection<V>>> removalPredicate
2688 = new Predicate<Map.Entry<K, Collection<V>>>() {
2689 @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
2690 return !c.contains(entry);
2691 }
2692 };
2693 return removeEntriesIf(removalPredicate);
2694 }
2695 }
2696 }
2697
2698 AbstractMultiset<K> keys;
2699
2700 @Override public Multiset<K> keys() {
2701 return (keys == null) ? keys = new Keys() : keys;
2702 }
2703
2704 class Keys extends Multimaps.Keys<K, V> {
2705 @Override Multimap<K, V> multimap() {
2706 return FilteredMultimap.this;
2707 }
2708
2709 @Override public int remove(Object o, int occurrences) {
2710 checkArgument(occurrences >= 0);
2711 Collection<V> values = unfiltered.asMap().get(o);
2712 if (values == null) {
2713 return 0;
2714 }
2715 int priorCount = 0;
2716 int removed = 0;
2717 Iterator<V> iterator = values.iterator();
2718 while (iterator.hasNext()) {
2719 if (satisfiesPredicate(o, iterator.next())) {
2720 priorCount++;
2721 if (removed < occurrences) {
2722 iterator.remove();
2723 removed++;
2724 }
2725 }
2726 }
2727 return priorCount;
2728 }
2729
2730 @Override Set<Multiset.Entry<K>> createEntrySet() {
2731 return new EntrySet();
2732 }
2733
2734 class EntrySet extends Multimaps.Keys<K, V>.KeysEntrySet {
2735 @Override public boolean removeAll(Collection<?> c) {
2736 return Sets.removeAllImpl(this, c);
2737 }
2738
2739 @Override public boolean retainAll(final Collection<?> c) {
2740 Predicate<Map.Entry<K, Collection<V>>> removalPredicate
2741 = new Predicate<Map.Entry<K, Collection<V>>>() {
2742 @Override public boolean apply(Map.Entry<K, Collection<V>> entry) {
2743 Multiset.Entry<K> multisetEntry
2744 = Multisets.immutableEntry(entry.getKey(), entry.getValue().size());
2745 return !c.contains(multisetEntry);
2746 }
2747 };
2748 return removeEntriesIf(removalPredicate);
2749 }
2750 }
2751 }
2752 }
2753
2754 // TODO(jlevy): Create methods that filter a SetMultimap or SortedSetMultimap.
2755 }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy