Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Copyright (C) 2007 The Guava Authors
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * http://www.apache.org/licenses/LICENSE-2.0
    *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package com.google.common.collect;
  
  import static com.google.common.base.Preconditions.checkArgument;
  import static com.google.common.base.Preconditions.checkNotNull;
  
  
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import  javax.annotation.Nullable;

Basic implementation of the Multimap interface. This class represents a multimap as a map that associates each key with a collection of values. All methods of Multimap are supported, including those specified as optional in the interface.

To implement a multimap, a subclass must define the method createCollection(), which creates an empty collection of values for a key.

The multimap constructor takes a map that has a single entry for each distinct key. When you insert a key-value pair with a key that isn't already in the multimap, AbstractMapBasedMultimap calls createCollection() to create the collection of values for that key. The subclass should not call createCollection() directly, and a new instance should be created every time the method is called.

For example, the subclass could pass a java.util.TreeMap during construction, and createCollection() could return a java.util.TreeSet, in which case the multimap's iterators would propagate through the keys and values in sorted order.

Keys and values may be null, as long as the underlying collection classes support null elements.

The collections created by createCollection() may or may not allow duplicates. If the collection, such as a Set, does not support duplicates, an added key-value pair will replace an existing pair with the same key and value, if such a pair is present. With collections like List that allow duplicates, the collection will keep the existing key-value pairs while adding a new pair.

This class is not threadsafe when any concurrent operations update the multimap, even if the underlying map and createCollection() method return threadsafe classes. Concurrent read operations will work correctly. To allow concurrent update operations, wrap your multimap with a call to Multimaps.synchronizedMultimap.

For serialization to work, the subclass must specify explicit readObject and writeObject methods.

Author(s):
Jared Levy
Louis Wasserman
  
  @GwtCompatible(emulated = true)
  abstract class AbstractMapBasedMultimap<K, V> extends AbstractMultimap<K, V>
      implements Serializable {
    /*
     * Here's an outline of the overall design.
     *
     * The map variable contains the collection of values associated with each
     * key. When a key-value pair is added to a multimap that didn't previously
     * contain any values for that key, a new collection generated by
     * createCollection is added to the map. That same collection instance
     * remains in the map as long as the multimap has any values for the key. If
     * all values for the key are removed, the key and collection are removed
    * from the map.
    *
    * The get method returns a WrappedCollection, which decorates the collection
    * in the map (if the key is present) or an empty collection (if the key is
    * not present). When the collection delegate in the WrappedCollection is
    * empty, the multimap may contain subsequently added values for that key. To
    * handle that situation, the WrappedCollection checks whether map contains
    * an entry for the provided key, and if so replaces the delegate.
    */
 
   private transient Map<K, Collection<V>> map;
   private transient int totalSize;

  
Creates a new multimap that uses the provided map.

Parameters:
map place to store the mapping from each key to its corresponding values
Throws:
IllegalArgumentException if map is not empty
 
   protected AbstractMapBasedMultimap(Map<K, Collection<V>> map) {
     checkArgument(map.isEmpty());
     this. = map;
   }

  
Used during deserialization only.
 
   final void setMap(Map<K, Collection<V>> map) {
     this. = map;
      = 0;
     for (Collection<V> values : map.values()) {
       checkArgument(!values.isEmpty());
        += values.size();
     }
   }

  
Creates an unmodifiable, empty collection of values.

This is used in removeAll on an empty key.

 
   }

  
Creates the collection of values for a single key.

Collections with weak, soft, or phantom references are not supported. Each call to createCollection should create a new instance.

The returned collection class determines whether duplicate key-value pairs are allowed.

Returns:
an empty collection of values
 
   abstract Collection<V> createCollection();

  
Creates the collection of values for an explicitly provided key. By default, it simply calls createCollection(), which is the correct behavior for most implementations. The LinkedHashMultimap class overrides it.

Parameters:
key key to associate with values in the collection
Returns:
an empty collection of values
 
   Collection<V> createCollection(@Nullable K key) {
     return createCollection();
   }
 
   Map<K, Collection<V>> backingMap() {
     return ;
   }
 
   // Query Operations
 
   public int size() {
     return ;
   }
 
   public boolean containsKey(@Nullable Object key) {
     return .containsKey(key);
   }
 
   // Modification Operations
 
   public boolean put(@Nullable K key, @Nullable V value) {
     Collection<V> collection = .get(key);
     if (collection == null) {
       collection = createCollection(key);
       if (collection.add(value)) {
         ++;
         .put(keycollection);
         return true;
       } else {
         throw new AssertionError("New Collection violated the Collection spec");
       }
     } else if (collection.add(value)) {
       ++;
       return true;
     } else {
       return false;
     }
   }
 
   private Collection<V> getOrCreateCollection(@Nullable K key) {
     Collection<V> collection = .get(key);
     if (collection == null) {
       collection = createCollection(key);
       .put(keycollection);
     }
     return collection;
   }
 
   // Bulk Operations
 
  

The returned collection is immutable.

 
   public Collection<V> replaceValues(@Nullable K keyIterable<? extends V> values) {
     Iterator<? extends V> iterator = values.iterator();
     if (!iterator.hasNext()) {
       return removeAll(key);
     }
 
     // TODO(user): investigate atomic failure?
     Collection<V> collection = getOrCreateCollection(key);
     Collection<V> oldValues = createCollection();
     oldValues.addAll(collection);
 
      -= collection.size();
     collection.clear();
 
     while (iterator.hasNext()) {
       if (collection.add(iterator.next())) {
         ++;
       }
     }
 
     return unmodifiableCollectionSubclass(oldValues);
   }

  

The returned collection is immutable.

 
   public Collection<V> removeAll(@Nullable Object key) {
     Collection<V> collection = .remove(key);
 
     if (collection == null) {
       return createUnmodifiableEmptyCollection();
     }
 
     Collection<V> output = createCollection();
     output.addAll(collection);
      -= collection.size();
     collection.clear();
 
     return unmodifiableCollectionSubclass(output);
   }
 
     // We don't deal with NavigableSet here yet for GWT reasons -- instead,
     // non-GWT TreeMultimap explicitly overrides this and uses NavigableSet.
     if (collection instanceof SortedSet) {
       return Collections.unmodifiableSortedSet((SortedSet<V>) collection);
     } else if (collection instanceof Set) {
       return Collections.unmodifiableSet((Set<V>) collection);
     } else if (collection instanceof List) {
       return Collections.unmodifiableList((List<V>) collection);
     } else {
       return Collections.unmodifiableCollection(collection);
     }
   }
 
   public void clear() {
     // Clear each collection, to make previously returned collections empty.
     for (Collection<V> collection : .values()) {
       collection.clear();
     }
     .clear();
      = 0;
   }
 
   // Views
 
  

The returned collection is not serializable.

 
   public Collection<V> get(@Nullable K key) {
     Collection<V> collection = .get(key);
     if (collection == null) {
       collection = createCollection(key);
     }
     return wrapCollection(keycollection);
   }

  
Generates a decorated collection that remains consistent with the values in the multimap for the provided key. Changes to the multimap may alter the returned collection, and vice versa.
 
   Collection<V> wrapCollection(@Nullable K keyCollection<V> collection) {
     // We don't deal with NavigableSet here yet for GWT reasons -- instead,
     // non-GWT TreeMultimap explicitly overrides this and uses NavigableSet.
     if (collection instanceof SortedSet) {
       return new WrappedSortedSet(key, (SortedSet<V>) collectionnull);
     } else if (collection instanceof Set) {
       return new WrappedSet(key, (Set<V>) collection);
     } else if (collection instanceof List) {
       return wrapList(key, (List<V>) collectionnull);
     } else {
       return new WrappedCollection(keycollectionnull);
     }
   }
 
   private List<V> wrapList(
       @Nullable K keyList<V> list, @Nullable WrappedCollection ancestor) {
     return (list instanceof RandomAccess)
         ? new RandomAccessWrappedList(keylistancestor)
         : new WrappedList(keylistancestor);
   }

  
Collection decorator that stays in sync with the multimap values for a key. There are two kinds of wrapped collections: full and subcollections. Both have a delegate pointing to the underlying collection class.

Full collections, identified by a null ancestor field, contain all multimap values for a given key. Its delegate is a value in AbstractMapBasedMultimap.map whenever the delegate is non-empty. The refreshIfEmpty, removeIfEmpty, and addToMap methods ensure that the WrappedCollection and map remain consistent.

A subcollection, such as a sublist, contains some of the values for a given key. Its ancestor field points to the full wrapped collection with all values for the key. The subcollection refreshIfEmpty, removeIfEmpty, and addToMap methods call the corresponding methods of the full wrapped collection.

 
   private class WrappedCollection extends AbstractCollection<V> {
     final K key;
     Collection<V> delegate;
     final WrappedCollection ancestor;
     final Collection<V> ancestorDelegate;
 
     WrappedCollection(@Nullable K keyCollection<V> delegate,
         @Nullable WrappedCollection ancestor) {
       this. = key;
       this. = delegate;
       this. = ancestor;
       this.
           = (ancestor == null) ? null : ancestor.getDelegate();
     }

    
If the delegate collection is empty, but the multimap has values for the key, replace the delegate with the new collection for the key.

For a subcollection, refresh its ancestor and validate that the ancestor delegate hasn't changed.

 
     void refreshIfEmpty() {
       if ( != null) {
         .refreshIfEmpty();
         if (.getDelegate() != ) {
           throw new ConcurrentModificationException();
         }
       } else if (.isEmpty()) {
         Collection<V> newDelegate = .get();
         if (newDelegate != null) {
            = newDelegate;
         }
       }
     }

    
If collection is empty, remove it from AbstractMapBasedMultimap.this.map. For subcollections, check whether the ancestor collection is empty.
 
     void removeIfEmpty() {
       if ( != null) {
         .removeIfEmpty();
       } else if (.isEmpty()) {
         .remove();
       }
     }
 
     K getKey() {
       return ;
     }

    
Add the delegate to the map. Other WrappedCollection methods should call this method after adding elements to a previously empty collection.

Subcollection add the ancestor's delegate instead.

 
     void addToMap() {
       if ( != null) {
         .addToMap();
       } else {
         .put();
       }
     }
 
     @Override public int size() {
       refreshIfEmpty();
       return .size();
     }
 
     @Override public boolean equals(@Nullable Object object) {
       if (object == this) {
         return true;
       }
       refreshIfEmpty();
       return .equals(object);
     }
 
     @Override public int hashCode() {
       refreshIfEmpty();
       return .hashCode();
     }
 
     @Override public String toString() {
       refreshIfEmpty();
       return .toString();
     }
 
     Collection<V> getDelegate() {
       return ;
     }
 
     @Override public Iterator<V> iterator() {
       refreshIfEmpty();
       return new WrappedIterator();
     }

    
Collection iterator for WrappedCollection.
 
     class WrappedIterator implements Iterator<V> {
       final Iterator<V> delegateIterator;
       final Collection<V> originalDelegate = ;
 
       WrappedIterator() {
       }
 
       WrappedIterator(Iterator<V> delegateIterator) {
         this. = delegateIterator;
       }

      
If the delegate changed since the iterator was created, the iterator is no longer valid.
 
       void validateIterator() {
         refreshIfEmpty();
         if ( != ) {
           throw new ConcurrentModificationException();
         }
       }
 
       @Override
       public boolean hasNext() {
         validateIterator();
         return .hasNext();
       }
 
       @Override
       public V next() {
         validateIterator();
         return .next();
       }
 
       @Override
       public void remove() {
         .remove();
         --;
         removeIfEmpty();
       }
 
       Iterator<V> getDelegateIterator() {
         validateIterator();
         return ;
       }
     }
 
     @Override public boolean add(V value) {
       refreshIfEmpty();
       boolean wasEmpty = .isEmpty();
       boolean changed = .add(value);
       if (changed) {
         ++;
         if (wasEmpty) {
           addToMap();
         }
       }
       return changed;
     }
 
       return ;
     }
 
     // The following methods are provided for better performance.
 
     @Override public boolean addAll(Collection<? extends V> collection) {
       if (collection.isEmpty()) {
         return false;
       }
       int oldSize = size();  // calls refreshIfEmpty
       boolean changed = .addAll(collection);
       if (changed) {
         int newSize = .size();
          += (newSize - oldSize);
         if (oldSize == 0) {
           addToMap();
         }
       }
       return changed;
     }
 
     @Override public boolean contains(Object o) {
       refreshIfEmpty();
       return .contains(o);
     }
 
     @Override public boolean containsAll(Collection<?> c) {
       refreshIfEmpty();
       return .containsAll(c);
     }
 
     @Override public void clear() {
       int oldSize = size();  // calls refreshIfEmpty
       if (oldSize == 0) {
         return;
       }
       .clear();
        -= oldSize;
       removeIfEmpty();       // maybe shouldn't be removed if this is a sublist
     }
 
     @Override public boolean remove(Object o) {
       refreshIfEmpty();
       boolean changed = .remove(o);
       if (changed) {
         --;
         removeIfEmpty();
       }
       return changed;
     }
 
     @Override public boolean removeAll(Collection<?> c) {
       if (c.isEmpty()) {
         return false;
       }
       int oldSize = size();  // calls refreshIfEmpty
       boolean changed = .removeAll(c);
       if (changed) {
         int newSize = .size();
          += (newSize - oldSize);
         removeIfEmpty();
       }
       return changed;
     }
 
     @Override public boolean retainAll(Collection<?> c) {
       checkNotNull(c);
       int oldSize = size();  // calls refreshIfEmpty
       boolean changed = .retainAll(c);
       if (changed) {
         int newSize = .size();
          += (newSize - oldSize);
         removeIfEmpty();
       }
       return changed;
     }
   }
 
   private Iterator<V> iteratorOrListIterator(Collection<V> collection) {
     return (collection instanceof List)
         ? ((List<V>) collection).listIterator()
         : collection.iterator();
   }

  
Set decorator that stays in sync with the multimap values for a key.
 
   private class WrappedSet extends WrappedCollection implements Set<V> {
     WrappedSet(@Nullable K keySet<V> delegate) {
       super(keydelegatenull);
     }
 
     @Override
     public boolean removeAll(Collection<?> c) {
       if (c.isEmpty()) {
         return false;
       }
       int oldSize = size();  // calls refreshIfEmpty
 
       // Guava issue 1013: AbstractSet and most JDK set implementations are
       // susceptible to quadratic removeAll performance on lists;
       // use a slightly smarter implementation here
       boolean changed = Sets.removeAllImpl((Set<V>) c);
       if (changed) {
         int newSize = .size();
          += (newSize - oldSize);
         removeIfEmpty();
       }
       return changed;
     }
   }

  
SortedSet decorator that stays in sync with the multimap values for a key.
 
   private class WrappedSortedSet extends WrappedCollection
       implements SortedSet<V> {
     WrappedSortedSet(@Nullable K keySortedSet<V> delegate,
         @Nullable WrappedCollection ancestor) {
       super(keydelegateancestor);
     }
 
       return (SortedSet<V>) getDelegate();
     }
 
     @Override
     public Comparator<? super V> comparator() {
       return getSortedSetDelegate().comparator();
     }
 
     @Override
     public V first() {
       refreshIfEmpty();
       return getSortedSetDelegate().first();
     }
 
     @Override
     public V last() {
       refreshIfEmpty();
       return getSortedSetDelegate().last();
     }
 
     @Override
     public SortedSet<V> headSet(V toElement) {
       refreshIfEmpty();
       return new WrappedSortedSet(
           getKey(), getSortedSetDelegate().headSet(toElement),
           (getAncestor() == null) ? this : getAncestor());
     }
 
     @Override
     public SortedSet<V> subSet(V fromElement, V toElement) {
       refreshIfEmpty();
       return new WrappedSortedSet(
           getKey(), getSortedSetDelegate().subSet(fromElementtoElement),
           (getAncestor() == null) ? this : getAncestor());
     }
 
     @Override
     public SortedSet<V> tailSet(V fromElement) {
       refreshIfEmpty();
       return new WrappedSortedSet(
           getKey(), getSortedSetDelegate().tailSet(fromElement),
           (getAncestor() == null) ? this : getAncestor());
     }
   }
 
   @GwtIncompatible("NavigableSet")
   class WrappedNavigableSet extends WrappedSortedSet implements NavigableSet<V> {
         @Nullable K keyNavigableSet<V> delegate, @Nullable WrappedCollection ancestor) {
       super(keydelegateancestor);
     }
 
     @Override
       return (NavigableSet<V>) super.getSortedSetDelegate();
     }
 
     @Override
     public V lower(V v) {
       return getSortedSetDelegate().lower(v);
     }
 
     @Override
     public V floor(V v) {
       return getSortedSetDelegate().floor(v);
     }
 
     @Override
     public V ceiling(V v) {
       return getSortedSetDelegate().ceiling(v);
     }
 
     @Override
     public V higher(V v) {
       return getSortedSetDelegate().higher(v);
     }
 
     @Override
     public V pollFirst() {
       return Iterators.pollNext(iterator());
     }
 
     @Override
     public V pollLast() {
       return Iterators.pollNext(descendingIterator());
     }
 
     private NavigableSet<V> wrap(NavigableSet<V> wrapped) {
       return new WrappedNavigableSet(wrapped,
           (getAncestor() == null) ? this : getAncestor());
     }
 
     @Override
     public NavigableSet<V> descendingSet() {
       return wrap(getSortedSetDelegate().descendingSet());
     }
 
     @Override
     public Iterator<V> descendingIterator() {
     }
 
     @Override
     public NavigableSet<V> subSet(
         V fromElementboolean fromInclusive, V toElementboolean toInclusive) {
       return wrap(
           getSortedSetDelegate().subSet(fromElementfromInclusivetoElementtoInclusive));
     }
 
     @Override
     public NavigableSet<V> headSet(V toElementboolean inclusive) {
       return wrap(getSortedSetDelegate().headSet(toElementinclusive));
     }
 
     @Override
     public NavigableSet<V> tailSet(V fromElementboolean inclusive) {
       return wrap(getSortedSetDelegate().tailSet(fromElementinclusive));
     }
   }

  
List decorator that stays in sync with the multimap values for a key.
 
   private class WrappedList extends WrappedCollection implements List<V> {
     WrappedList(@Nullable K keyList<V> delegate,
         @Nullable WrappedCollection ancestor) {
       super(keydelegateancestor);
     }
 
     List<V> getListDelegate() {
       return (List<V>) getDelegate();
     }
 
     @Override
     public boolean addAll(int indexCollection<? extends V> c) {
       if (c.isEmpty()) {
         return false;
       }
       int oldSize = size();  // calls refreshIfEmpty
       boolean changed = getListDelegate().addAll(indexc);
       if (changed) {
         int newSize = getDelegate().size();
          += (newSize - oldSize);
         if (oldSize == 0) {
           addToMap();
         }
       }
       return changed;
     }
 
     @Override
     public V get(int index) {
       refreshIfEmpty();
       return getListDelegate().get(index);
     }
 
     @Override
     public V set(int index, V element) {
       refreshIfEmpty();
       return getListDelegate().set(indexelement);
     }
 
     @Override
     public void add(int index, V element) {
       refreshIfEmpty();
       boolean wasEmpty = getDelegate().isEmpty();
       getListDelegate().add(indexelement);
       ++;
       if (wasEmpty) {
         addToMap();
       }
     }
 
     @Override
     public V remove(int index) {
       refreshIfEmpty();
       V value = getListDelegate().remove(index);
       --;
       removeIfEmpty();
       return value;
     }
 
     @Override
     public int indexOf(Object o) {
       refreshIfEmpty();
       return getListDelegate().indexOf(o);
     }
 
     @Override
     public int lastIndexOf(Object o) {
       refreshIfEmpty();
       return getListDelegate().lastIndexOf(o);
     }
 
     @Override
     public ListIterator<V> listIterator() {
       refreshIfEmpty();
       return new WrappedListIterator();
     }
 
     @Override
     public ListIterator<V> listIterator(int index) {
       refreshIfEmpty();
       return new WrappedListIterator(index);
     }
 
     @Override
     public List<V> subList(int fromIndexint toIndex) {
       refreshIfEmpty();
       return wrapList(getKey(),
           getListDelegate().subList(fromIndextoIndex),
           (getAncestor() == null) ? this : getAncestor());
     }

    
ListIterator decorator.
 
     private class WrappedListIterator extends WrappedIterator
         implements ListIterator<V> {
       WrappedListIterator() {}
 
       public WrappedListIterator(int index) {
         super(getListDelegate().listIterator(index));
       }
 
       private ListIterator<V> getDelegateListIterator() {
         return (ListIterator<V>) getDelegateIterator();
       }
 
       @Override
       public boolean hasPrevious() {
         return getDelegateListIterator().hasPrevious();
       }
 
       @Override
       public V previous() {
         return getDelegateListIterator().previous();
       }
 
       @Override
       public int nextIndex() {
         return getDelegateListIterator().nextIndex();
       }
 
       @Override
       public int previousIndex() {
         return getDelegateListIterator().previousIndex();
       }
 
       @Override
       public void set(V value) {
         getDelegateListIterator().set(value);
       }
 
       @Override
       public void add(V value) {
         boolean wasEmpty = isEmpty();
         getDelegateListIterator().add(value);
         ++;
         if (wasEmpty) {
           addToMap();
         }
       }
     }
   }

  
List decorator that stays in sync with the multimap values for a key and supports rapid random access.
 
   private class RandomAccessWrappedList extends WrappedList
       implements RandomAccess {
     RandomAccessWrappedList(@Nullable K keyList<V> delegate,
         @Nullable WrappedCollection ancestor) {
       super(keydelegateancestor);
     }
   }
 
   Set<K> createKeySet() {
     // TreeMultimap uses NavigableKeySet explicitly, but we don't handle that here for GWT
     // compatibility reasons
     return ( instanceof SortedMap)
         ? new SortedKeySet((SortedMap<K, Collection<V>>) ) : new KeySet();
   }
 
   private class KeySet extends Maps.KeySet<K, Collection<V>> {

    
This is usually the same as map, except when someone requests a subcollection of a SortedKeySet.
 
     final Map<K, Collection<V>> subMap;
 
     KeySet(final Map<K, Collection<V>> subMap) {
       this. = subMap;
     }
 
     @Override
     Map<K, Collection<V>> map() {
       return ;
     }
 
     @Override public Iterator<K> iterator() {
       final Iterator<Map.Entry<K, Collection<V>>> entryIterator
           = .entrySet().iterator();
       return new Iterator<K>() {
         Map.Entry<K, Collection<V>> entry;
 
         @Override
         public boolean hasNext() {
           return entryIterator.hasNext();
         }
         @Override
         public K next() {
            = entryIterator.next();
           return .getKey();
         }
         @Override
         public void remove() {
           Iterators.checkRemove( != null);
           Collection<V> collection = .getValue();
           entryIterator.remove();
            -= collection.size();
           collection.clear();
         }
       };
     }
 
     // The following methods are included for better performance.
 
     @Override public boolean remove(Object key) {
       int count = 0;
       Collection<V> collection = .remove(key);
       if (collection != null) {
         count = collection.size();
         collection.clear();
          -= count;
       }
       return count > 0;
     }
 
     @Override
     public void clear() {
       Iterators.clear(iterator());
     }
 
     @Override public boolean containsAll(Collection<?> c) {
       return .keySet().containsAll(c);
     }
 
     @Override public boolean equals(@Nullable Object object) {
       return this == object || this..keySet().equals(object);
     }
 
     @Override public int hashCode() {
       return .keySet().hashCode();
     }
   }
 
   private class SortedKeySet extends KeySet implements SortedSet<K> {
 
     SortedKeySet(SortedMap<K, Collection<V>> subMap) {
       super(subMap);
     }
 
     SortedMap<K, Collection<V>> sortedMap() {
       return (SortedMap<K, Collection<V>>) ;
     }
    @Override
    public Comparator<? super K> comparator() {
      return sortedMap().comparator();
    }
    @Override
    public K first() {
      return sortedMap().firstKey();
    }
    @Override
    public SortedSet<K> headSet(K toElement) {
      return new SortedKeySet(sortedMap().headMap(toElement));
    }
    @Override
    public K last() {
      return sortedMap().lastKey();
    }
    @Override
    public SortedSet<K> subSet(K fromElement, K toElement) {
      return new SortedKeySet(sortedMap().subMap(fromElementtoElement));
    }
    @Override
    public SortedSet<K> tailSet(K fromElement) {
      return new SortedKeySet(sortedMap().tailMap(fromElement));
    }
  }
  @GwtIncompatible("NavigableSet")
  class NavigableKeySet extends SortedKeySet implements NavigableSet<K> {
    NavigableKeySet(NavigableMap<K, Collection<V>> subMap) {
      super(subMap);
    }
    @Override
    NavigableMap<K, Collection<V>> sortedMap() {
      return (NavigableMap<K, Collection<V>>) super.sortedMap();
    }
    @Override
    public K lower(K k) {
      return sortedMap().lowerKey(k);
    }
    @Override
    public K floor(K k) {
      return sortedMap().floorKey(k);
    }
    @Override
    public K ceiling(K k) {
      return sortedMap().ceilingKey(k);
    }
    @Override
    public K higher(K k) {
      return sortedMap().higherKey(k);
    }
    @Override
    public K pollFirst() {
      return Iterators.pollNext(iterator());
    }
    @Override
    public K pollLast() {
      return Iterators.pollNext(descendingIterator());
    }
    @Override
    public NavigableSet<K> descendingSet() {
      return new NavigableKeySet(sortedMap().descendingMap());
    }
    @Override
    public Iterator<K> descendingIterator() {
      return descendingSet().iterator();
    }
    @Override
    public NavigableSet<K> headSet(K toElement) {
      return headSet(toElementfalse);
    }
    @Override
    public NavigableSet<K> headSet(K toElementboolean inclusive) {
      return new NavigableKeySet(sortedMap().headMap(toElementinclusive));
    }
    @Override
    public NavigableSet<K> subSet(K fromElement, K toElement) {
      return subSet(fromElementtruetoElementfalse);
    }
    @Override
    public NavigableSet<K> subSet(
        K fromElementboolean fromInclusive, K toElementboolean toInclusive) {
      return new NavigableKeySet(
          sortedMap().subMap(fromElementfromInclusivetoElementtoInclusive));
    }
    @Override
    public NavigableSet<K> tailSet(K fromElement) {
      return tailSet(fromElementtrue);
    }
    @Override
    public NavigableSet<K> tailSet(K fromElementboolean inclusive) {
      return new NavigableKeySet(sortedMap().tailMap(fromElementinclusive));
    }
  }

  
Removes all values for the provided key. Unlike removeAll, it returns the number of removed mappings.
  private int removeValuesForKey(Object key) {
    Collection<V> collection = Maps.safeRemove(key);
    int count = 0;
    if (collection != null) {
      count = collection.size();
      collection.clear();
       -= count;
    }
    return count;
  }

  

The iterator generated by the returned collection traverses the values for one key, followed by the values of a second key, and so on.

  @Override public Collection<V> values() {
    return super.values();
  }
  /*
   * TODO(kevinb): should we copy this javadoc to each concrete class, so that
   * classes like LinkedHashMultimap that need to say something different are
   * still able to {@inheritDoc} all the way from Multimap?
   */

  

The iterator generated by the returned collection traverses the values for one key, followed by the values of a second key, and so on.

Each entry is an immutable snapshot of a key-value mapping in the multimap, taken at the time the entry is returned by a method call to the collection or its iterator.

  public Collection<Map.Entry<K, V>> entries() {
    return super.entries();
  }

  
Returns an iterator across all key-value map entries, used by entries().iterator() and values().iterator(). The default behavior, which traverses the values for one key, the values for a second key, and so on, suffices for most AbstractMapBasedMultimap implementations.

Returns:
an iterator across map entries
    return new EntryIterator();
  }

  
Iterator across all key-value pairs.
  private class EntryIterator implements Iterator<Map.Entry<K, V>> {
    final Iterator<Map.Entry<K, Collection<V>>> keyIterator;
    K key;
    EntryIterator() {
       = .entrySet().iterator();
      if (.hasNext()) {
        findValueIteratorAndKey();
      } else {
         = Iterators.emptyModifiableIterator();
      }
    }
    void