mirror of
https://github.com/apache/commons-collections.git
synced 2025-02-17 23:44:48 +00:00
Fix put methods, optimize clear method, fix formatting
bug 29440 git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@171009 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
92cee86ea2
commit
9072508ad0
@ -15,31 +15,51 @@
|
||||
*/
|
||||
package org.apache.commons.collections.map;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.collections.Factory;
|
||||
import org.apache.commons.collections.MultiMap;
|
||||
import org.apache.commons.collections.iterators.EmptyIterator;
|
||||
import org.apache.commons.collections.iterators.IteratorChain;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A MultiValueMap decorates another map, allowing it to have
|
||||
* more than one value for a key. The values of the map will be
|
||||
* Collection objects. The types of which can be specified using
|
||||
* either a Class object or a Factory which creates Collection
|
||||
* objects.
|
||||
* more than one value for a key.
|
||||
* <p>
|
||||
* A <code>MultiMap</code> is a Map with slightly different semantics.
|
||||
* Putting a value into the map will add the value to a Collection at that key.
|
||||
* Getting a value will return a Collection, holding all the values put to that key.
|
||||
* <p>
|
||||
* This implementation is a decorator, allowing any Map implementation
|
||||
* to be used as the base.
|
||||
* <p>
|
||||
* In addition, this implementation allows the type of collection used
|
||||
* for the values to be controlled. By default, an <code>ArrayList</code>
|
||||
* is used, however a <code>Class</code> to instantiate may be specified,
|
||||
* or a factory that returns a <code>Collection</code> instance.
|
||||
*
|
||||
* @author <a href="mailto:jcarman@apache.org">James Carman</a>
|
||||
* @author James Carman
|
||||
* @author Christopher Berry
|
||||
* @author James Strachan
|
||||
* @author Steve Downey
|
||||
* @author Stephen Colebourne
|
||||
* @author Julien Buret
|
||||
* @author Serhiy Yevtushenko
|
||||
* @version $Revision: $ $Date: $
|
||||
* @since Commons Collections 3.2
|
||||
*/
|
||||
public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
|
||||
/** The factory for creating value collections. */
|
||||
private final Factory collectionFactory;
|
||||
private Collection values;
|
||||
/** The cached values. */
|
||||
private transient Collection values;
|
||||
|
||||
/**
|
||||
* Creates a map which wraps the given map and
|
||||
@ -47,8 +67,8 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
*
|
||||
* @param map the map to wrap
|
||||
*/
|
||||
public static Map decorate(Map map) {
|
||||
return new MultiValueMap(map);
|
||||
public static MultiValueMap decorate(Map map) {
|
||||
return new MultiValueMap(map, new ReflectionFactory(ArrayList.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -58,8 +78,8 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
* @param map the map to wrap
|
||||
* @param collectionClass the type of the collection class
|
||||
*/
|
||||
public static Map decorate(Map map, Class collectionClass) {
|
||||
return new MultiValueMap(map, collectionClass);
|
||||
public static MultiValueMap decorate(Map map, Class collectionClass) {
|
||||
return new MultiValueMap(map, new ReflectionFactory(collectionClass));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -69,29 +89,17 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
* @param map the map to decorate
|
||||
* @param collectionFactory the collection factory (must return a Collection object).
|
||||
*/
|
||||
public static Map decorate(Map map, Factory collectionFactory) {
|
||||
public static MultiValueMap decorate(Map map, Factory collectionFactory) {
|
||||
return new MultiValueMap(map, collectionFactory);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Creates a MultiValueMap which wraps the given map and
|
||||
* maps keys to ArrayLists.
|
||||
*
|
||||
* @param map the map to wrap
|
||||
* Creates a MultiValueMap based on a <code>HashMap</code> and
|
||||
* storing the multiple values in an <code>ArrayList</code>.
|
||||
*/
|
||||
protected MultiValueMap(Map map) {
|
||||
this(map, ArrayList.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MultiValueMap which decorates the given <code>map</code> and
|
||||
* maps keys to collections of type <code>collectionClass</code>.
|
||||
*
|
||||
* @param map the map to wrap
|
||||
* @param collectionClass the type of the collection class
|
||||
*/
|
||||
protected MultiValueMap(Map map, Class collectionClass) {
|
||||
this(map, new ReflectionFactory(collectionClass));
|
||||
public MultiValueMap() {
|
||||
this(new HashMap(), new ReflectionFactory(ArrayList.class));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,26 +107,29 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
* creates the value collections using the supplied <code>collectionFactory</code>.
|
||||
*
|
||||
* @param map the map to decorate
|
||||
* @param collectionFactory the collection factory (must return a Collection object).
|
||||
* @param collectionFactory the collection factory which must return a Collection instance
|
||||
*/
|
||||
protected MultiValueMap(Map map, Factory collectionFactory) {
|
||||
super(map);
|
||||
if (collectionFactory == null) {
|
||||
throw new IllegalArgumentException("The factory must not be null");
|
||||
}
|
||||
this.collectionFactory = collectionFactory;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Clear the map.
|
||||
* <p>
|
||||
* This clears each collection in the map, and so may be slow.
|
||||
*/
|
||||
public void clear() {
|
||||
Set pairs = getMap().entrySet();
|
||||
Iterator pairsIterator = pairs.iterator();
|
||||
while(pairsIterator.hasNext()) {
|
||||
Map.Entry keyValuePair = (Map.Entry) pairsIterator.next();
|
||||
Collection coll = (Collection) keyValuePair.getValue();
|
||||
coll.clear();
|
||||
}
|
||||
// If you believe that you have GC issues here, try uncommenting this code
|
||||
// Set pairs = getMap().entrySet();
|
||||
// Iterator pairsIterator = pairs.iterator();
|
||||
// while (pairsIterator.hasNext()) {
|
||||
// Map.Entry keyValuePair = (Map.Entry) pairsIterator.next();
|
||||
// Collection coll = (Collection) keyValuePair.getValue();
|
||||
// coll.clear();
|
||||
// }
|
||||
getMap().clear();
|
||||
}
|
||||
|
||||
@ -175,26 +186,30 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a specific value from map.
|
||||
* Adds the value to the collection associated with the specified key.
|
||||
* <p>
|
||||
* The item is removed from the collection mapped to the specified key.
|
||||
* Other values attached to that key are unaffected.
|
||||
* <p>
|
||||
* If the last value for a key is removed, <code>null</code> will be returned
|
||||
* from a subsequant <code>get(key)</code>.
|
||||
* Unlike a normal <code>Map</code> the previous value is not replaced.
|
||||
* Instead the new value is added to the collection stored against the key.
|
||||
*
|
||||
* @param key the key to remove from
|
||||
* @param value the value to remove
|
||||
* @return the value removed (which was passed in), null if nothing removed
|
||||
* @param key the key to store against
|
||||
* @param value the value to add to the collection at the key
|
||||
* @return the value added if the map changed and null if the map did not change
|
||||
*/
|
||||
public Object put(Object key, Object value) {
|
||||
Collection c = getCollection(key);
|
||||
if(c == null) {
|
||||
c = (Collection) collectionFactory.create();
|
||||
getMap().put(key, c);
|
||||
boolean result = false;
|
||||
Collection coll = getCollection(key);
|
||||
if (coll == null) {
|
||||
coll = createCollection(1);
|
||||
result = coll.add(value);
|
||||
if (coll.size() > 0) {
|
||||
// only add if non-zero size to maintain class state
|
||||
getMap().put(key, coll);
|
||||
result = false;
|
||||
}
|
||||
boolean results = c.add(value);
|
||||
return (results ? value : null);
|
||||
} else {
|
||||
result = coll.add(value);
|
||||
}
|
||||
return (result ? value : null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,7 +264,8 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a collection of values to the collection associated with the specified key.
|
||||
* Adds a collection of values to the collection associated with
|
||||
* the specified key.
|
||||
*
|
||||
* @param key the key to store against
|
||||
* @param values the values to add to the collection at the key, null ignored
|
||||
@ -261,11 +277,18 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
}
|
||||
Collection coll = getCollection(key);
|
||||
if (coll == null) {
|
||||
coll = (Collection) collectionFactory.create();
|
||||
coll = createCollection(values.size());
|
||||
boolean result = coll.addAll(values);
|
||||
if (coll.size() > 0) {
|
||||
// only add if non-zero size to maintain class state
|
||||
getMap().put(key, coll);
|
||||
result = false;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return coll.addAll(values);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an iterator for the collection mapped to the specified key.
|
||||
@ -276,8 +299,7 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
public Iterator iterator(Object key) {
|
||||
if (!containsKey(key)) {
|
||||
return EmptyIterator.INSTANCE;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return new ValuesIterator(key);
|
||||
}
|
||||
}
|
||||
@ -297,11 +319,29 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new instance of the map value Collection container
|
||||
* using the factory.
|
||||
* <p>
|
||||
* This method can be overridden to perform your own processing
|
||||
* instead of using the factory.
|
||||
*
|
||||
* @param size the collection size that is about to be added
|
||||
* @return the new collection
|
||||
*/
|
||||
protected Collection createCollection(int size) {
|
||||
return (Collection) collectionFactory.create();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/**
|
||||
* Inner class that provides the values view.
|
||||
*/
|
||||
private class Values extends AbstractCollection {
|
||||
public Iterator iterator() {
|
||||
final IteratorChain chain = new IteratorChain();
|
||||
for(Iterator i = keySet().iterator(); i.hasNext();) {
|
||||
chain.addIterator(new ValuesIterator(i.next()));
|
||||
for (Iterator it = keySet().iterator(); it.hasNext();) {
|
||||
chain.addIterator(new ValuesIterator(it.next()));
|
||||
}
|
||||
return chain;
|
||||
}
|
||||
@ -315,6 +355,9 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class that provides the values iterator.
|
||||
*/
|
||||
private class ValuesIterator implements Iterator {
|
||||
private final Object key;
|
||||
private final Collection values;
|
||||
@ -342,6 +385,9 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class that provides a simple reflection factory.
|
||||
*/
|
||||
private static class ReflectionFactory implements Factory {
|
||||
private final Class clazz;
|
||||
|
||||
@ -352,10 +398,10 @@ public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
|
||||
public Object create() {
|
||||
try {
|
||||
return clazz.newInstance();
|
||||
}
|
||||
catch(Exception e) {
|
||||
throw new RuntimeException("Cannot instantiate class " + clazz + ".", e);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Cannot instantiate class: " + clazz, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2001-2005 The Apache Software Foundation
|
||||
* Copyright 2005 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -28,7 +28,7 @@ import java.util.Collection;
|
||||
import org.apache.commons.collections.IteratorUtils;
|
||||
|
||||
/**
|
||||
* TestMultiValueMap
|
||||
* TestMultiValueMap.
|
||||
*
|
||||
* @author <a href="mailto:jcarman@apache.org">James Carman</a>
|
||||
* @since Commons Collections 3.2
|
||||
@ -93,7 +93,7 @@ public class TestMultiValueMap extends TestCase {
|
||||
}
|
||||
|
||||
private MultiValueMap createTestMap(Class collectionClass) {
|
||||
final MultiValueMap map = new MultiValueMap(new HashMap(), collectionClass);
|
||||
final MultiValueMap map = MultiValueMap.decorate(new HashMap(), collectionClass);
|
||||
map.put("one", "uno");
|
||||
map.put("one", "un");
|
||||
map.put("two", "dos");
|
||||
|
Loading…
x
Reference in New Issue
Block a user