1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.collections4.multimap; 18 19 import java.io.IOException; 20 import java.io.ObjectInputStream; 21 import java.io.ObjectOutputStream; 22 import java.io.Serializable; 23 import java.util.ArrayList; 24 import java.util.Collection; 25 import java.util.HashMap; 26 import java.util.Map; 27 28 import org.apache.commons.collections4.MultiValuedMap; 29 30 /** 31 * Implements a {@code ListValuedMap}, using a {@link HashMap} to provide data 32 * storage and {@link ArrayList}s as value collections. This is the standard 33 * implementation of a ListValuedMap. 34 * <p> 35 * <strong>Note that ArrayListValuedHashMap is not synchronized and is not 36 * thread-safe.</strong> If you wish to use this map from multiple threads 37 * concurrently, you must use appropriate synchronization. This class may throw 38 * exceptions when accessed by concurrent threads without synchronization. 39 * </p> 40 * 41 * @param <K> the type of the keys in this map 42 * @param <V> the type of the values in this map 43 * @since 4.1 44 */ 45 public class ArrayListValuedHashMap<K, V> extends AbstractListValuedMap<K, V> 46 implements Serializable { 47 48 /** Serialization Version */ 49 private static final long serialVersionUID = 20151118L; 50 51 /** 52 * The initial map capacity used when none specified in constructor. 53 */ 54 private static final int DEFAULT_INITIAL_MAP_CAPACITY = 16; 55 56 /** 57 * The initial list capacity when using none specified in constructor. 58 */ 59 private static final int DEFAULT_INITIAL_LIST_CAPACITY = 3; 60 61 /** 62 * The initial list capacity when creating a new value collection. 63 */ 64 private final int initialListCapacity; 65 66 /** 67 * Creates an empty ArrayListValuedHashMap with the default initial 68 * map capacity (16) and the default initial list capacity (3). 69 */ 70 public ArrayListValuedHashMap() { 71 this(DEFAULT_INITIAL_MAP_CAPACITY, DEFAULT_INITIAL_LIST_CAPACITY); 72 } 73 74 /** 75 * Creates an empty ArrayListValuedHashMap with the default initial 76 * map capacity (16) and the specified initial list capacity. 77 * 78 * @param initialListCapacity the initial capacity used for value collections 79 */ 80 public ArrayListValuedHashMap(final int initialListCapacity) { 81 this(DEFAULT_INITIAL_MAP_CAPACITY, initialListCapacity); 82 } 83 84 /** 85 * Creates an empty ArrayListValuedHashMap with the specified initial 86 * map and list capacities. 87 * 88 * @param initialMapCapacity the initial hashmap capacity 89 * @param initialListCapacity the initial capacity used for value collections 90 */ 91 public ArrayListValuedHashMap(final int initialMapCapacity, final int initialListCapacity) { 92 super(new HashMap<>(initialMapCapacity)); 93 this.initialListCapacity = initialListCapacity; 94 } 95 96 /** 97 * Creates an ArrayListValuedHashMap copying all the mappings of the given map. 98 * 99 * @param map a {@code Map} to copy into this map 100 */ 101 public ArrayListValuedHashMap(final Map<? extends K, ? extends V> map) { 102 this(map.size(), DEFAULT_INITIAL_LIST_CAPACITY); 103 super.putAll(map); 104 } 105 106 /** 107 * Creates an ArrayListValuedHashMap copying all the mappings of the given map. 108 * 109 * @param map a {@code MultiValuedMap} to copy into this map 110 */ 111 public ArrayListValuedHashMap(final MultiValuedMap<? extends K, ? extends V> map) { 112 this(map.size(), DEFAULT_INITIAL_LIST_CAPACITY); 113 super.putAll(map); 114 } 115 116 @Override 117 protected ArrayList<V> createCollection() { 118 return new ArrayList<>(initialListCapacity); 119 } 120 121 /** 122 * Deserializes an instance from an ObjectInputStream. 123 * 124 * @param in The source ObjectInputStream. 125 * @throws IOException Any of the usual Input/Output related exceptions. 126 * @throws ClassNotFoundException A class of a serialized object cannot be found. 127 */ 128 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { 129 in.defaultReadObject(); 130 setMap(new HashMap<>()); 131 doReadObject(in); 132 } 133 134 /** 135 * Trims the capacity of all value collections to their current size. 136 */ 137 public void trimToSize() { 138 for (final Collection<V> coll : getMap().values()) { 139 final ArrayList<V> list = (ArrayList<V>) coll; 140 list.trimToSize(); 141 } 142 } 143 144 /** 145 * Serializes this object to an ObjectOutputStream. 146 * 147 * @param out the target ObjectOutputStream. 148 * @throws IOException thrown when an I/O errors occur writing to the target stream. 149 */ 150 private void writeObject(final ObjectOutputStream out) throws IOException { 151 out.defaultWriteObject(); 152 doWriteObject(out); 153 } 154 155 }