COLLECTIONS-871 Added LinkedHashSetValuedLinkedHashMap
This commit is contained in:
parent
064530e1e0
commit
2d0b85ac65
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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.collections4.multimap;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.collections4.MultiValuedMap;
|
||||
|
||||
/**
|
||||
* Implements a {@code SetValuedMap}, using a {@link LinkedHashMap} to provide data
|
||||
* storage and {@link LinkedHashSet}s as value collections. This is the standard
|
||||
* implementation of a SetValuedMap.
|
||||
* <p>
|
||||
* <strong>Note that LinkedHashSetValuedLinkedHashMap 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.
|
||||
* </p>
|
||||
*
|
||||
* @param <K> the type of the keys in this map
|
||||
* @param <V> the type of the values in this map
|
||||
* @since 4.5
|
||||
*/
|
||||
public class LinkedHashSetValuedLinkedHashMap<K, V> extends AbstractSetValuedMap<K, V>
|
||||
implements Serializable {
|
||||
|
||||
/** Serialization Version */
|
||||
private static final long serialVersionUID = 20241020L;
|
||||
|
||||
/**
|
||||
* The initial map capacity used when none specified in constructor.
|
||||
*/
|
||||
private static final int DEFAULT_INITIAL_MAP_CAPACITY = 16;
|
||||
|
||||
/**
|
||||
* The initial set capacity when using none specified in constructor.
|
||||
*/
|
||||
private static final int DEFAULT_INITIAL_SET_CAPACITY = 3;
|
||||
|
||||
/**
|
||||
* The initial list capacity when creating a new value collection.
|
||||
*/
|
||||
private final int initialSetCapacity;
|
||||
|
||||
/**
|
||||
* Creates an empty LinkedHashSetValuedHashMap with the default initial
|
||||
* map capacity (16) and the default initial set capacity (3).
|
||||
*/
|
||||
public LinkedHashSetValuedLinkedHashMap() {
|
||||
this(DEFAULT_INITIAL_MAP_CAPACITY, DEFAULT_INITIAL_SET_CAPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty LinkedHashSetValuedHashMap with the default initial
|
||||
* map capacity (16) and the specified initial set capacity.
|
||||
*
|
||||
* @param initialSetCapacity the initial capacity used for value collections
|
||||
*/
|
||||
public LinkedHashSetValuedLinkedHashMap(final int initialSetCapacity) {
|
||||
this(DEFAULT_INITIAL_MAP_CAPACITY, initialSetCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty LinkedHashSetValuedHashMap with the specified initial
|
||||
* map and list capacities.
|
||||
*
|
||||
* @param initialMapCapacity the initial hashmap capacity
|
||||
* @param initialSetCapacity the initial capacity used for value collections
|
||||
*/
|
||||
public LinkedHashSetValuedLinkedHashMap(final int initialMapCapacity, final int initialSetCapacity) {
|
||||
super(new LinkedHashMap<>(initialMapCapacity));
|
||||
this.initialSetCapacity = initialSetCapacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an LinkedHashSetValuedHashMap copying all the mappings of the given map.
|
||||
*
|
||||
* @param map a {@code Map} to copy into this map
|
||||
*/
|
||||
public LinkedHashSetValuedLinkedHashMap(final Map<? extends K, ? extends V> map) {
|
||||
this(map.size(), DEFAULT_INITIAL_SET_CAPACITY);
|
||||
super.putAll(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an LinkedHashSetValuedHashMap copying all the mappings of the given map.
|
||||
*
|
||||
* @param map a {@code MultiValuedMap} to copy into this map
|
||||
*/
|
||||
public LinkedHashSetValuedLinkedHashMap(final MultiValuedMap<? extends K, ? extends V> map) {
|
||||
this(map.size(), DEFAULT_INITIAL_SET_CAPACITY);
|
||||
super.putAll(map);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LinkedHashSet<V> createCollection() {
|
||||
return new LinkedHashSet<>(initialSetCapacity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes an instance from an ObjectInputStream.
|
||||
*
|
||||
* @param in The source ObjectInputStream.
|
||||
* @throws IOException Any of the usual Input/Output related exceptions.
|
||||
* @throws ClassNotFoundException A class of a serialized object cannot be found.
|
||||
*/
|
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
setMap(new LinkedHashMap<>());
|
||||
doReadObject(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes this object to an ObjectOutputStream.
|
||||
*
|
||||
* @param out the target ObjectOutputStream.
|
||||
* @throws IOException thrown when an I/O errors occur writing to the target stream.
|
||||
*/
|
||||
private void writeObject(final ObjectOutputStream out) throws IOException {
|
||||
out.defaultWriteObject();
|
||||
doWriteObject(out);
|
||||
}
|
||||
|
||||
}
|
|
@ -193,9 +193,9 @@ public class HashSetValuedHashMapTest<K, V> extends AbstractMultiValuedMapTest<K
|
|||
|
||||
// public void testCreate() throws Exception {
|
||||
// writeExternalFormToDisk((java.io.Serializable) makeObject(),
|
||||
// "src/test/resources/data/test/HashSetValuedHashMap.emptyCollection.version4.1.obj");
|
||||
// "src/test/resources/org/apache/commons/collections4/data/test/HashSetValuedHashMap.emptyCollection.version4.1.obj");
|
||||
// writeExternalFormToDisk((java.io.Serializable) makeFullMap(),
|
||||
// "src/test/resources/data/test/HashSetValuedHashMap.fullCollection.version4.1.obj");
|
||||
// "src/test/resources/org/apache/commons/collections4/data/test/HashSetValuedHashMap.fullCollection.version4.1.obj");
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* 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.collections4.multimap;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.collections4.MultiValuedMap;
|
||||
import org.apache.commons.collections4.SetValuedMap;
|
||||
import org.apache.commons.collections4.collection.AbstractCollectionTest;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Tests {@link LinkedHashSetValuedLinkedHashMap}.
|
||||
*/
|
||||
public class LinkedHashSetValuedLinkedHashMapTest<K, V> extends AbstractMultiValuedMapTest<K, V> {
|
||||
|
||||
public LinkedHashSetValuedLinkedHashMapTest() {
|
||||
super(LinkedHashSetValuedLinkedHashMapTest.class.getSimpleName());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getIterationBehaviour() {
|
||||
return AbstractCollectionTest.UNORDERED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHashSetValue() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiValuedMap<K, V> makeConfirmedMap() {
|
||||
return new LinkedHashSetValuedLinkedHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SetValuedMap<K, V> makeObject() {
|
||||
return new LinkedHashSetValuedLinkedHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCompatibilityVersion() {
|
||||
return "4.5"; // LinkedHashSetValuedLinkedHashMap was added in version 4.5
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLinkedHashSetValuedLinkedHashMap_2() {
|
||||
final Map<K, V> map = new HashMap<>();
|
||||
final SetValuedMap<K, V> map1;
|
||||
final SetValuedMap<K, V> map2;
|
||||
|
||||
map.put((K) "A", (V) "W");
|
||||
map.put((K) "B", (V) "X");
|
||||
map.put((K) "C", (V) "F");
|
||||
map1 = new LinkedHashSetValuedLinkedHashMap<>(map);
|
||||
assertEquals(1, map1.get((K) "A").size());
|
||||
|
||||
map.remove("A");
|
||||
map.remove("B");
|
||||
map.remove("C");
|
||||
map2 = new LinkedHashSetValuedLinkedHashMap<>(map);
|
||||
assertEquals("{}", map2.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHashSetValueHashMap() {
|
||||
final SetValuedMap<K, V> setMap = new LinkedHashSetValuedLinkedHashMap<>(4);
|
||||
assertEquals(0, setMap.get((K) "whatever").size());
|
||||
|
||||
final Set<V> set = setMap.get((K) "A");
|
||||
set.add((V) "W");
|
||||
set.add((V) "X");
|
||||
set.add((V) "F");
|
||||
assertEquals(3, setMap.get((K) "A").size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHashSetValueHashMap_1() {
|
||||
final MultiValuedMap<K, V> map = new ArrayListValuedHashMap<>();
|
||||
final SetValuedMap<K, V> map1;
|
||||
final SetValuedMap<K, V> map2 = makeObject();
|
||||
final SetValuedMap<K, V> map3;
|
||||
|
||||
map.put((K) "A", (V) "W");
|
||||
map.put((K) "A", (V) "X");
|
||||
map.put((K) "A", (V) "F");
|
||||
map1 = new LinkedHashSetValuedLinkedHashMap<>(map);
|
||||
assertEquals(3, map1.get((K) "A").size());
|
||||
map2.put((K) "A", (V) "X");
|
||||
map2.put((K) "A", (V) "F");
|
||||
map2.put((K) "A", (V) "W");
|
||||
assertEquals(map1, map2);
|
||||
assertEquals(map1.hashCode(), map2.hashCode());
|
||||
|
||||
map.remove("A");
|
||||
map3 = new LinkedHashSetValuedLinkedHashMap<>(map);
|
||||
assertEquals("{}", map3.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testSetValuedMapAdd() {
|
||||
final SetValuedMap<K, V> setMap = makeObject();
|
||||
assertTrue(setMap.get((K) "whatever") instanceof Set);
|
||||
|
||||
final Set<V> set = setMap.get((K) "A");
|
||||
assertTrue(set.add((V) "a1"));
|
||||
assertTrue(set.add((V) "a2"));
|
||||
assertFalse(set.add((V) "a1"));
|
||||
assertEquals(2, setMap.size());
|
||||
assertTrue(setMap.containsKey("A"));
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Test
|
||||
public void testSetValuedMapEqualsHashCodeContract() {
|
||||
final SetValuedMap map1 = makeObject();
|
||||
final SetValuedMap map2 = makeObject();
|
||||
|
||||
map1.put("a", "a1");
|
||||
map1.put("a", "a2");
|
||||
map2.put("a", "a2");
|
||||
map2.put("a", "a1");
|
||||
assertEquals(map1, map2);
|
||||
assertEquals(map1.hashCode(), map2.hashCode());
|
||||
|
||||
map2.put("a", "a2");
|
||||
assertEquals(map1, map2);
|
||||
assertEquals(map1.hashCode(), map2.hashCode());
|
||||
|
||||
map2.put("a", "a3");
|
||||
assertNotSame(map1, map2);
|
||||
assertNotSame(map1.hashCode(), map2.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testSetValuedMapRemove() {
|
||||
final SetValuedMap<K, V> setMap = makeObject();
|
||||
assertTrue(setMap.get((K) "whatever") instanceof Set);
|
||||
|
||||
final Set<V> set = setMap.get((K) "A");
|
||||
assertTrue(set.add((V) "a1"));
|
||||
assertTrue(set.add((V) "a2"));
|
||||
assertFalse(set.add((V) "a1"));
|
||||
assertEquals(2, setMap.size());
|
||||
assertTrue(setMap.containsKey("A"));
|
||||
|
||||
assertTrue(set.remove("a1"));
|
||||
assertTrue(set.remove("a2"));
|
||||
assertFalse(set.remove("a1"));
|
||||
|
||||
assertEquals(0, setMap.size());
|
||||
assertFalse(setMap.containsKey("A"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testSetValuedMapRemoveViaIterator() {
|
||||
final SetValuedMap<K, V> setMap = makeObject();
|
||||
assertTrue(setMap.get((K) "whatever") instanceof Set);
|
||||
|
||||
final Set<V> set = setMap.get((K) "A");
|
||||
set.add((V) "a1");
|
||||
set.add((V) "a2");
|
||||
set.add((V) "a1");
|
||||
|
||||
final Iterator<V> it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
it.remove();
|
||||
}
|
||||
assertEquals(0, setMap.size());
|
||||
assertFalse(setMap.containsKey("A"));
|
||||
}
|
||||
|
||||
// public void testCreate() throws Exception {
|
||||
// writeExternalFormToDisk((java.io.Serializable) makeObject(),
|
||||
// "src/test/resources/org/apache/commons/collections4/data/test/LinkedHashSetValuedLinkedHashMap.emptyCollection.version4.5.obj");
|
||||
// writeExternalFormToDisk((java.io.Serializable) makeFullMap(),
|
||||
// "src/test/resources/org/apache/commons/collections4/data/test/LinkedHashSetValuedLinkedHashMap.fullCollection.version4.5.obj");
|
||||
// }
|
||||
|
||||
}
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue