    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.collections4.multimap;
    018
    019import java.io.IOException;
    020import java.io.ObjectInputStream;
    021import java.io.ObjectOutputStream;
    022import java.io.Serializable;
    023import java.util.HashMap;
    024import java.util.HashSet;
    025import java.util.Map;
    026
    027import org.apache.commons.collections4.MultiValuedMap;
    028
    029/**
    030 * Implements a {@code SetValuedMap}, using a {@link HashMap} to provide data
    031 * storage and {@link HashSet}s as value collections. This is the standard
    032 * implementation of a SetValuedMap.
    033 * <p>
    034 * <strong>Note that HashSetValuedHashMap is not synchronized and is not
    035 * thread-safe.</strong> If you wish to use this map from multiple threads
    036 * concurrently, you must use appropriate synchronization. This class may throw
    037 * exceptions when accessed by concurrent threads without synchronization.
    038 *
    039 * @param <K> the type of the keys in this map
    040 * @param <V> the type of the values in this map
    041 * @since 4.1
    042 */
    043public class HashSetValuedHashMap<K, V> extends AbstractSetValuedMap<K, V>
    044    implements Serializable {
    045
    046    /** Serialization Version */
    047    private static final long serialVersionUID = 20151118L;
    048
    049    /**
    050     * The initial map capacity used when none specified in constructor.
    051     */
    052    private static final int DEFAULT_INITIAL_MAP_CAPACITY = 16;
    053
    054    /**
    055     * The initial set capacity when using none specified in constructor.
    056     */
    057    private static final int DEFAULT_INITIAL_SET_CAPACITY = 3;
    058
    059    /**
    060     * The initial list capacity when creating a new value collection.
    061     */
    062    private final int initialSetCapacity;
    063
    064    /**
    065     * Creates an empty HashSetValuedHashMap with the default initial
    066     * map capacity (16) and the default initial set capacity (3).
    067     */
    068    public HashSetValuedHashMap() {
    069        this(DEFAULT_INITIAL_MAP_CAPACITY, DEFAULT_INITIAL_SET_CAPACITY);
    070    }
    071
    072    /**
    073     * Creates an empty HashSetValuedHashMap with the default initial
    074     * map capacity (16) and the specified initial set capacity.
    075     *
    076     * @param initialSetCapacity  the initial capacity used for value collections
    077     */
    078    public HashSetValuedHashMap(final int initialSetCapacity) {
    079        this(DEFAULT_INITIAL_MAP_CAPACITY, initialSetCapacity);
    080    }
    081
    082    /**
    083     * Creates an empty HashSetValuedHashMap with the specified initial
    084     * map and list capacities.
    085     *
    086     * @param initialMapCapacity  the initial hashmap capacity
    087     * @param initialSetCapacity  the initial capacity used for value collections
    088     */
    089    public HashSetValuedHashMap(final int initialMapCapacity, final int initialSetCapacity) {
    090        super(new HashMap<K, HashSet<V>>(initialMapCapacity));
    091        this.initialSetCapacity = initialSetCapacity;
    092    }
    093
    094    /**
    095     * Creates an HashSetValuedHashMap copying all the mappings of the given map.
    096     *
    097     * @param map a <code>MultiValuedMap</code> to copy into this map
    098     */
    099    public HashSetValuedHashMap(final MultiValuedMap<? extends K, ? extends V> map) {
    100        this(map.size(), DEFAULT_INITIAL_SET_CAPACITY);
    101        super.putAll(map);
    102    }
    103
    104    /**
    105     * Creates an HashSetValuedHashMap copying all the mappings of the given map.
    106     *
    107     * @param map a <code>Map</code> to copy into this map
    108     */
    109    public HashSetValuedHashMap(final Map<? extends K, ? extends V> map) {
    110        this(map.size(), DEFAULT_INITIAL_SET_CAPACITY);
    111        super.putAll(map);
    112    }
    113
    114    // -----------------------------------------------------------------------
    115    @Override
    116    protected HashSet<V> createCollection() {
    117        return new HashSet<>(initialSetCapacity);
    118    }
    119
    120    // -----------------------------------------------------------------------
    121    private void writeObject(final ObjectOutputStream oos) throws IOException {
    122        oos.defaultWriteObject();
    123        doWriteObject(oos);
    124    }
    125
    126    private void readObject(final ObjectInputStream ois) throws IOException, ClassNotFoundException {
    127        ois.defaultReadObject();
    128        setMap(new HashMap<K, HashSet<V>>());
    129        doReadObject(ois);
    130    }
    131
    132}