public class LinkedListMultimap<K,V> extends AbstractMultimap<K,V> implements ListMultimap<K,V>, java.io.Serializable
ListMultimap
that supports deterministic iteration order for both
keys and values. The iteration order is preserved across non-distinct key values. For example,
for the following multimap definition:
Multimap<K, V> multimap = LinkedListMultimap.create();
multimap.put(key1, foo);
multimap.put(key2, bar);
multimap.put(key1, baz);
... the iteration order for AbstractMultimap.keys()
is [key1, key2, key1]
, and similarly for
entries()
. Unlike LinkedHashMultimap
, the iteration order is kept consistent
between keys, entries and values. For example, calling:
multimap.remove(key1, foo);
changes the entries iteration order to [key2=bar, key1=baz]
and the key iteration
order to [key2, key1]
. The entries()
iterator returns mutable map entries, and
replaceValues(K, java.lang.Iterable<? extends V>)
attempts to preserve iteration order as much as possible.
The collections returned by AbstractMultimap.keySet()
and AbstractMultimap.asMap
iterate through the keys in
the order they were first added to the multimap. Similarly, get(K)
, removeAll(java.lang.Object)
, and
replaceValues(K, java.lang.Iterable<? extends V>)
return collections that iterate through the values in the order they were
added. The collections generated by entries()
, AbstractMultimap.keys()
, and values()
iterate across the key-value mappings in the order they were added to the multimap.
The values()
and entries()
methods both return a List
, instead of
the Collection
specified by the ListMultimap
interface.
The methods get(K)
, AbstractMultimap.keySet()
, AbstractMultimap.keys()
, values()
, entries()
, and AbstractMultimap.asMap
return collections that are views of the multimap. If the
multimap is modified while an iteration over any of those collections is in progress, except
through the iterator's methods, the results of the iteration are undefined.
Keys and values may be null. All optional multimap methods are supported, and all returned views are modifiable.
This class is not threadsafe when any concurrent operations update the multimap. Concurrent
read operations will work correctly. To allow concurrent update operations, wrap your multimap
with a call to Multimaps.synchronizedListMultimap(com.google.common.collect.ListMultimap<K, V>)
.
See the Guava User Guide article on Multimap
.
Modifier and Type | Class and Description |
---|---|
private class |
LinkedListMultimap.DistinctKeyIterator
An
Iterator over distinct keys in key head order. |
private static class |
LinkedListMultimap.KeyList<K,V> |
private static class |
LinkedListMultimap.Node<K,V> |
private class |
LinkedListMultimap.NodeIterator
An
Iterator over all nodes. |
private class |
LinkedListMultimap.ValueForKeyIterator
A
ListIterator over values for a specified key. |
AbstractMultimap.Entries, AbstractMultimap.EntrySet, AbstractMultimap.Values
Modifier and Type | Field and Description |
---|---|
private LinkedListMultimap.Node<K,V> |
head |
private java.util.Map<K,LinkedListMultimap.KeyList<K,V>> |
keyToKeyList |
private int |
modCount |
private static long |
serialVersionUID |
private int |
size |
private LinkedListMultimap.Node<K,V> |
tail |
Modifier | Constructor and Description |
---|---|
(package private) |
LinkedListMultimap() |
private |
LinkedListMultimap(int expectedKeys) |
private |
LinkedListMultimap(Multimap<? extends K,? extends V> multimap) |
Modifier and Type | Method and Description |
---|---|
private LinkedListMultimap.Node<K,V> |
addNode(K key,
V value,
LinkedListMultimap.Node<K,V> nextSibling)
Adds a new node for the specified key-value pair before the specified
nextSibling
element, or at the end of the list if nextSibling is null. |
private static void |
checkElement(java.lang.Object node)
Helper method for verifying that an iterator element is present.
|
void |
clear()
Removes all key-value pairs from the multimap, leaving it empty.
|
boolean |
containsKey(java.lang.Object key)
Returns
true if this multimap contains at least one key-value pair with the key key . |
boolean |
containsValue(java.lang.Object value)
Returns
true if this multimap contains at least one key-value pair with the value
value . |
static <K,V> LinkedListMultimap<K,V> |
create()
Creates a new, empty
LinkedListMultimap with the default initial capacity. |
static <K,V> LinkedListMultimap<K,V> |
create(int expectedKeys)
Constructs an empty
LinkedListMultimap with enough capacity to hold the specified
number of keys without rehashing. |
static <K,V> LinkedListMultimap<K,V> |
create(Multimap<? extends K,? extends V> multimap)
Constructs a
LinkedListMultimap with the same mappings as the specified Multimap . |
(package private) java.util.Map<K,java.util.Collection<V>> |
createAsMap() |
(package private) java.util.List<java.util.Map.Entry<K,V>> |
createEntries() |
(package private) Multiset<K> |
createKeys() |
(package private) java.util.Set<K> |
createKeySet() |
(package private) java.util.List<V> |
createValues() |
java.util.List<java.util.Map.Entry<K,V>> |
entries()
Returns a view collection of all key-value pairs contained in this multimap, as
Map.Entry
instances. |
(package private) java.util.Iterator<java.util.Map.Entry<K,V>> |
entryIterator() |
java.util.List<V> |
get(K key)
Returns a view collection of the values associated with
key in this multimap, if any. |
private java.util.List<V> |
getCopy(java.lang.Object key) |
boolean |
isEmpty()
Returns
true if this multimap contains no key-value pairs. |
boolean |
put(K key,
V value)
Stores a key-value pair in the multimap.
|
private void |
readObject(java.io.ObjectInputStream stream) |
java.util.List<V> |
removeAll(java.lang.Object key)
Removes all values associated with the key
key . |
private void |
removeAllNodes(java.lang.Object key)
Removes all nodes for the specified key.
|
private void |
removeNode(LinkedListMultimap.Node<K,V> node)
Removes the specified node from the linked list.
|
java.util.List<V> |
replaceValues(K key,
java.lang.Iterable<? extends V> values)
Stores a collection of values with the same key, replacing any existing values for that key.
|
int |
size()
Returns the number of key-value pairs in this multimap.
|
java.util.List<V> |
values()
Returns a view collection containing the value from each key-value pair contained in
this multimap, without collapsing duplicates (so
values().size() == size() ). |
private void |
writeObject(java.io.ObjectOutputStream stream) |
asMap, containsEntry, entrySpliterator, equals, hashCode, keys, keySet, putAll, putAll, remove, toString, valueIterator, valueSpliterator
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
asMap, equals
private transient LinkedListMultimap.Node<K,V> head
private transient LinkedListMultimap.Node<K,V> tail
private transient java.util.Map<K,LinkedListMultimap.KeyList<K,V>> keyToKeyList
private transient int size
private transient int modCount
private static final long serialVersionUID
LinkedListMultimap()
private LinkedListMultimap(int expectedKeys)
public static <K,V> LinkedListMultimap<K,V> create()
LinkedListMultimap
with the default initial capacity.public static <K,V> LinkedListMultimap<K,V> create(int expectedKeys)
LinkedListMultimap
with enough capacity to hold the specified
number of keys without rehashing.expectedKeys
- the expected number of distinct keysjava.lang.IllegalArgumentException
- if expectedKeys
is negativepublic static <K,V> LinkedListMultimap<K,V> create(Multimap<? extends K,? extends V> multimap)
LinkedListMultimap
with the same mappings as the specified Multimap
. The new multimap has the same Multimap.entries()
iteration order as the
input multimap.multimap
- the multimap whose contents are copied to this multimapprivate LinkedListMultimap.Node<K,V> addNode(K key, V value, LinkedListMultimap.Node<K,V> nextSibling)
nextSibling
element, or at the end of the list if nextSibling
is null. Note: if nextSibling
is specified, it MUST be for an node for the same key
!private void removeNode(LinkedListMultimap.Node<K,V> node)
Iterator
classes. See also removeAllNodes(Object)
.private void removeAllNodes(java.lang.Object key)
private static void checkElement(java.lang.Object node)
public int size()
Multimap
Note: this method does not return the number of distinct keys in the multimap,
which is given by keySet().size()
or asMap().size()
. See the opening section of
the Multimap
class documentation for clarification.
public boolean isEmpty()
Multimap
true
if this multimap contains no key-value pairs. Equivalent to size()
== 0
, but can in some cases be more efficient.public boolean containsKey(java.lang.Object key)
Multimap
true
if this multimap contains at least one key-value pair with the key key
.containsKey
in interface Multimap<K,V>
public boolean containsValue(java.lang.Object value)
Multimap
true
if this multimap contains at least one key-value pair with the value
value
.containsValue
in interface Multimap<K,V>
containsValue
in class AbstractMultimap<K,V>
public java.util.List<V> replaceValues(K key, java.lang.Iterable<? extends V> values)
If values
is empty, this is equivalent to removeAll(key)
.
If any entries for the specified key
already exist in the multimap, their values are
changed in-place without affecting the iteration order.
The returned list is immutable and implements RandomAccess
.
replaceValues
in interface ListMultimap<K,V>
replaceValues
in interface Multimap<K,V>
replaceValues
in class AbstractMultimap<K,V>
private java.util.List<V> getCopy(java.lang.Object key)
public java.util.List<V> removeAll(java.lang.Object key)
key
.
Once this method returns, key
will not be mapped to any values, so it will not
appear in Multimap.keySet()
, Multimap.asMap()
, or any other views.
Because the values for a given key may have duplicates and follow the insertion ordering,
this method returns a List
, instead of the Collection
specified in
the Multimap
interface.
The returned list is immutable and implements RandomAccess
.
public void clear()
Multimap
public java.util.List<V> get(K key)
key
in this multimap, if any.
Note that when containsKey(key)
is false, this returns an empty collection, not null
.
Changes to the returned collection will update the underlying multimap, and vice versa.
Because the values for a given key may have duplicates and follow the insertion ordering,
this method returns a List
, instead of the Collection
specified in
the Multimap
interface.
If the multimap is modified while an iteration over the list is in progress (except through
the iterator's own add
, set
or remove
operations) the results of the
iteration are undefined.
The returned list is not serializable and does not have random access.
java.util.Set<K> createKeySet()
createKeySet
in class AbstractMultimap<K,V>
Multiset<K> createKeys()
createKeys
in class AbstractMultimap<K,V>
public java.util.List<V> values()
values().size() == size()
).
Changes to the returned collection will update the underlying multimap, and vice versa. However, adding to the returned collection is not possible.
The iterator generated by the returned collection traverses the values in the order they
were added to the multimap. Because the values may have duplicates and follow the insertion
ordering, this method returns a List
, instead of the Collection
specified in
the ListMultimap
interface.
java.util.List<V> createValues()
createValues
in class AbstractMultimap<K,V>
public java.util.List<java.util.Map.Entry<K,V>> entries()
Map.Entry
instances.
Changes to the returned collection or the entries it contains will update the underlying multimap, and vice versa. However, adding to the returned collection is not possible.
The iterator generated by the returned collection traverses the entries in the order they
were added to the multimap. Because the entries may have duplicates and follow the insertion
ordering, this method returns a List
, instead of the Collection
specified in
the ListMultimap
interface.
An entry's Map.Entry.getKey()
method always returns the same key, regardless of what
happens subsequently. As long as the corresponding key-value mapping is not removed from the
multimap, Map.Entry.getValue()
returns the value from the multimap, which may change over
time, and Map.Entry.setValue(V)
modifies that value. Removing the mapping from the multimap
does not alter the value returned by getValue()
, though a subsequent setValue()
call won't update the multimap but will lead to a revised value being returned by getValue()
.
java.util.List<java.util.Map.Entry<K,V>> createEntries()
createEntries
in class AbstractMultimap<K,V>
java.util.Iterator<java.util.Map.Entry<K,V>> entryIterator()
entryIterator
in class AbstractMultimap<K,V>
java.util.Map<K,java.util.Collection<V>> createAsMap()
createAsMap
in class AbstractMultimap<K,V>
private void writeObject(java.io.ObjectOutputStream stream) throws java.io.IOException
java.io.IOException
private void readObject(java.io.ObjectInputStream stream) throws java.io.IOException, java.lang.ClassNotFoundException
java.io.IOException
java.lang.ClassNotFoundException