You need to store multiple values for a single key in a Map
. Instead of a one-to-one relationship
between keys and values, you need a Map
that provides one-to-many relationships
between keys and values.
Use a MultiMap
. A MultiMap
maintains a collection of values for a given key. When a
new key/value pair is added to a MultiMap
, the value is added to the collection
of values for that key. The MultiMap
also provides a way to remove a specific key/value pair. The following
example demonstrates the use of MultiMap
:
import org.apache.commons.collections.MultiMap; import org.apache.commons.collections.MultiHashMap; MultiMap map = new MultiHashMap( ); map.put( "ONE", "TEST" ); map.put( "TWO", "PICNIC" ); map.put( "ONE", "HELLO" ); map.put( "TWO", "TESTIMONY" ); Set keySet = map.keySet( ); Iterator keyIterator = keySet.iterator( ); while( keyIterator.hasNext( ) ) { Object key = keyIterator.next( ); System.out.print( "Key: " + key + ", " ); Collection values = (Collection) map.get( key ); Iterator valuesIterator = values.iterator( ); while( valuesIterator.hasNext( ) ) { System.out.print( "Value: " + valuesIterator.next( ) + ". " ); } System.out.print( "\n" ); }
Each key in a MultiMap
corresponds to a collection of values. This example produces the
following output while iterating through all values for each key:
Key: ONE, Value: TEST. Value: HELLO Key: TWO, Value: PICNIC. Value: Testimony
In a traditional Map
, a key is
removed with map.remove( )
; this method removes the specified key from the map. In a
MultiMap
, a specific key/value pair
can be removed from a key's value collection. When removing a specific
pair, the value is extracted from a key's value collection. Example 5-10 demonstrates the use of
a MultiMap.remove()
method.
Example 5-10. Using MultiMap.remove( )
package com.discursive.jccook.collections.map; import org.apache.commons.collections.*; import java.util.*; public class MultiMapExample { public static void main(String[] args) { MultiMapExample example = new MultiMapExample( ); example.start( ); } public void start( ) { MultiMap map = new MultiHashMap( ); map.put( "ONE", "TEST" ); map.put( "ONE", "WAR" ); map.put( "ONE", "CAR" ); map.put( "ONE", "WEST" ); map.put( "TWO", "SKY" ); map.put( "TWO", "WEST" ); map.put( "TWO", "SCHOOL" ); // At this point "ONE" should correspond to "TEST", "WAR", "CAR", "WEST" map.remove( "ONE", "WAR" ); map.remove( "ONE", "CAR" ); // The size of this collection should be two "TEST", "WEST" Collection oneCollection = (Collection) map.get("ONE"); // This collection should be "TEST", "WEST", "SKY", "WEST", "SCHOOL" Collection values = map.values( ); } }
The MultiMap
is relevant when
one object is associated with many different objects. A sensible example
would be a MultiMap
of people to the
languages they speak fluently, and the following example demonstrates
such a Map
:
MultiMap languageAbility = new MultiHashMap( ); languageAbility.put( "Tom", "French" ); languageAbility.put( "Chris", "Spanish" ); languageAbility.put( "Chris", "German" ); languageAbility.put( "John", "Arabic" ); languageAbility.put( "Tom", "Pashto" ); // What languages does Tom speak? Collection languages = (Collection) languageAbility.get("Tom"); Iterator languageIterator = languages.iterator( ); while( languageIterator.hasNext( ) ) { System.out.println( "Tom speaks " + languageIterator.next( ) ); }
If you had to locate people who were fluent in a given language,
it would be equally as valid to use languages as keys and names as
values. One could then query the MultiMap
for a list of people who speak a
certain language. If your system contains two collections of objects
that have a
many-to-many relationship, these relationships can be managed with two instances of
MultiMap
.