📄 multivaluemap.java
字号:
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 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.FunctorException;
import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.iterators.EmptyIterator;
import org.apache.commons.collections.iterators.IteratorChain;
/**
* A MultiValueMap decorates another map, allowing it to have
* 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.
* <p>
* <strong>Note that MultiValueMap is not synchronized and is not thread-safe.</strong>
* If you wish to use this map from multiple threads concurrently, you must use
* appropriate synchronization. This class may throw exceptions when accessed
* by concurrent threads without synchronization.
*
* @author James Carman
* @author Christopher Berry
* @author James Strachan
* @author Steve Downey
* @author Stephen Colebourne
* @author Julien Buret
* @author Serhiy Yevtushenko
* @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
* @since Commons Collections 3.2
*/
public class MultiValueMap extends AbstractMapDecorator implements MultiMap {
/** The factory for creating value collections. */
private final Factory collectionFactory;
/** The cached values. */
private transient Collection values;
/**
* Creates a map which wraps the given map and
* maps keys to ArrayLists.
*
* @param map the map to wrap
*/
public static MultiValueMap decorate(Map map) {
return new MultiValueMap(map, new ReflectionFactory(ArrayList.class));
}
/**
* Creates a map 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
*/
public static MultiValueMap decorate(Map map, Class collectionClass) {
return new MultiValueMap(map, new ReflectionFactory(collectionClass));
}
/**
* Creates a map which decorates the given <code>map</code> and
* 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).
*/
public static MultiValueMap decorate(Map map, Factory collectionFactory) {
return new MultiValueMap(map, collectionFactory);
}
//-----------------------------------------------------------------------
/**
* Creates a MultiValueMap based on a <code>HashMap</code> and
* storing the multiple values in an <code>ArrayList</code>.
*/
public MultiValueMap() {
this(new HashMap(), new ReflectionFactory(ArrayList.class));
}
/**
* Creates a MultiValueMap which decorates the given <code>map</code> and
* creates the value collections using the supplied <code>collectionFactory</code>.
*
* @param map the map to decorate
* @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.
*/
public void 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();
}
/**
* Removes a specific value from map.
* <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>.
*
* @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
*/
public Object remove(Object key, Object value) {
Collection valuesForKey = getCollection(key);
if (valuesForKey == null) {
return null;
}
boolean removed = valuesForKey.remove(value);
if (removed == false) {
return null;
}
if (valuesForKey.isEmpty()) {
remove(key);
}
return value;
}
/**
* Checks whether the map contains the value specified.
* <p>
* This checks all collections against all keys for the value, and thus could be slow.
*
* @param value the value to search for
* @return true if the map contains the value
*/
public boolean containsValue(Object value) {
Set pairs = getMap().entrySet();
if (pairs == null) {
return false;
}
Iterator pairsIterator = pairs.iterator();
while (pairsIterator.hasNext()) {
Map.Entry keyValuePair = (Map.Entry) pairsIterator.next();
Collection coll = (Collection) keyValuePair.getValue();
if (coll.contains(value)) {
return true;
}
}
return false;
}
/**
* Adds the value to the collection associated with the specified key.
* <p>
* 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 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) {
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;
}
} else {
result = coll.add(value);
}
return (result ? value : null);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -