View Javadoc
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    *      https://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.MultiMapUtils;
29  import org.apache.commons.collections4.MultiValuedMap;
30  
31  /**
32   * Implements a {@code ListValuedMap}, using a {@link HashMap} to provide data
33   * storage and {@link ArrayList}s as value collections. This is the standard
34   * implementation of a ListValuedMap.
35   * <p>
36   * <strong>Note that ArrayListValuedHashMap is not synchronized and is not
37   * thread-safe.</strong> If you wish to use this map from multiple threads
38   * concurrently, you must use appropriate synchronization. This class may throw
39   * exceptions when accessed by concurrent threads without synchronization.
40   * </p>
41   *
42   * @param <K> The type of the keys in this map
43   * @param <V> The type of the values in this map
44   * @since 4.1
45   */
46  public class ArrayListValuedHashMap<K, V> extends AbstractListValuedMap<K, V>
47      implements Serializable {
48  
49      /** Serialization Version */
50      private static final long serialVersionUID = 20151118L;
51  
52      /**
53       * The initial map capacity used when none specified in constructor.
54       */
55      private static final int DEFAULT_INITIAL_MAP_CAPACITY = 16;
56  
57      /**
58       * The initial list capacity when using none specified in constructor.
59       */
60      private static final int DEFAULT_INITIAL_LIST_CAPACITY = 3;
61  
62      /**
63       * The initial list capacity when creating a new value collection.
64       */
65      private final int initialListCapacity;
66  
67      /**
68       * Creates an empty ArrayListValuedHashMap with the default initial
69       * map capacity (16) and the default initial list capacity (3).
70       */
71      public ArrayListValuedHashMap() {
72          this(DEFAULT_INITIAL_MAP_CAPACITY, DEFAULT_INITIAL_LIST_CAPACITY);
73      }
74  
75      /**
76       * Creates an empty ArrayListValuedHashMap with the default initial
77       * map capacity (16) and the specified initial list capacity.
78       *
79       * @param initialListCapacity  The initial capacity used for value collections
80       */
81      public ArrayListValuedHashMap(final int initialListCapacity) {
82          this(DEFAULT_INITIAL_MAP_CAPACITY, initialListCapacity);
83      }
84  
85      /**
86       * Creates an empty ArrayListValuedHashMap with the specified initial
87       * map and list capacities.
88       *
89       * @param initialMapCapacity  The initial hashmap capacity
90       * @param initialListCapacity  The initial capacity used for value collections
91       */
92      public ArrayListValuedHashMap(final int initialMapCapacity, final int initialListCapacity) {
93          super(new HashMap<>(initialMapCapacity));
94          this.initialListCapacity = initialListCapacity;
95      }
96  
97      /**
98       * Creates an ArrayListValuedHashMap copying all the mappings of the given map.
99       *
100      * @param map A {@code Map} to copy into this map
101      */
102     public ArrayListValuedHashMap(final Map<? extends K, ? extends V> map) {
103         this(map.size(), DEFAULT_INITIAL_LIST_CAPACITY);
104         super.putAll(map);
105     }
106 
107     /**
108      * Creates an ArrayListValuedHashMap copying all the mappings of the given map.
109      *
110      * @param map A {@code MultiValuedMap} to copy into this map
111      */
112     public ArrayListValuedHashMap(final MultiValuedMap<? extends K, ? extends V> map) {
113         this(map.size(), DEFAULT_INITIAL_LIST_CAPACITY);
114         super.putAll(map);
115     }
116 
117     @Override
118     protected ArrayList<V> createCollection() {
119         return new ArrayList<>(initialListCapacity);
120     }
121 
122     @Override
123     public ArrayListValuedHashMap<V, K> inverted() {
124         return MultiMapUtils.invert(this, new ArrayListValuedHashMap<V, K>());
125     }
126 
127     /**
128      * Deserializes an instance from an ObjectInputStream.
129      *
130      * @param in The source ObjectInputStream.
131      * @throws IOException            Any of the usual Input/Output related exceptions.
132      * @throws ClassNotFoundException A class of a serialized object cannot be found.
133      */
134     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
135         in.defaultReadObject();
136         setMap(new HashMap<>());
137         doReadObject(in);
138     }
139 
140     /**
141      * Trims the capacity of all value collections to their current size.
142      */
143     public void trimToSize() {
144         for (final Collection<V> coll : getMap().values()) {
145             final ArrayList<V> list = (ArrayList<V>) coll;
146             list.trimToSize();
147         }
148     }
149 
150     /**
151      * Serializes this object to an ObjectOutputStream.
152      *
153      * @param out The target ObjectOutputStream.
154      * @throws IOException thrown when an I/O errors occur writing to the target stream.
155      */
156     private void writeObject(final ObjectOutputStream out) throws IOException {
157         out.defaultWriteObject();
158         doWriteObject(out);
159     }
160 
161 }