All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.collect.MultimapBuilder Maven / Gradle / Ivy

There is a newer version: 33.3.0-jre-r3
Show newest version
/*
 * Copyright (C) 2013 The Guava Authors
 *
 * Licensed 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 com.google.common.collect;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.CollectPreconditions.checkNonnegative;

import com.google.common.annotations.GwtCompatible;
import com.google.common.base.Supplier;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * An immutable builder for {@link Multimap} instances, letting you independently select the desired
 * behaviors (for example, ordering) of the backing map and value-collections. Example:
 *
 * 
{@code
 * ListMultimap errorsByUser =
 *     MultimapBuilder.linkedHashKeys().arrayListValues().build();
 * SortedSetMultimap methodsForName =
 *     MultimapBuilder.treeKeys().treeSetValues(this::compareMethods).build();
 * }
* *

{@code MultimapBuilder} instances are immutable. Invoking a configuration method has no effect * on the receiving instance; you must store and use the new builder instance it returns instead. * *

The generated multimaps are serializable if the key and value types are serializable, unless * stated otherwise in one of the configuration methods. * * @author Louis Wasserman * @param An upper bound on the key type of the generated multimap. * @param An upper bound on the value type of the generated multimap. * @since 16.0 */ @GwtCompatible @ElementTypesAreNonnullByDefault public abstract class MultimapBuilder { /* * Leaving K and V as upper bounds rather than the actual key and value types allows type * parameters to be left implicit more often. CacheBuilder uses the same technique. */ private MultimapBuilder() {} private static final int DEFAULT_EXPECTED_KEYS = 8; /** Uses a hash table to map keys to value collections. */ public static MultimapBuilderWithKeys<@Nullable Object> hashKeys() { return hashKeys(DEFAULT_EXPECTED_KEYS); } /** * Uses a hash table to map keys to value collections, initialized to expect the specified number * of keys. * * @throws IllegalArgumentException if {@code expectedKeys < 0} */ public static MultimapBuilderWithKeys<@Nullable Object> hashKeys(int expectedKeys) { checkNonnegative(expectedKeys, "expectedKeys"); return new MultimapBuilderWithKeys<@Nullable Object>() { @Override Map> createMap() { return Platform.newHashMapWithExpectedSize(expectedKeys); } }; } /** * Uses a hash table to map keys to value collections. * *

The collections returned by {@link Multimap#keySet()}, {@link Multimap#keys()}, and {@link * Multimap#asMap()} will iterate through the keys in the order that they were first added to the * multimap, save that if all values associated with a key are removed and then the key is added * back into the multimap, that key will come last in the key iteration order. */ public static MultimapBuilderWithKeys<@Nullable Object> linkedHashKeys() { return linkedHashKeys(DEFAULT_EXPECTED_KEYS); } /** * Uses an hash table to map keys to value collections, initialized to expect the specified number * of keys. * *

The collections returned by {@link Multimap#keySet()}, {@link Multimap#keys()}, and {@link * Multimap#asMap()} will iterate through the keys in the order that they were first added to the * multimap, save that if all values associated with a key are removed and then the key is added * back into the multimap, that key will come last in the key iteration order. */ public static MultimapBuilderWithKeys<@Nullable Object> linkedHashKeys(int expectedKeys) { checkNonnegative(expectedKeys, "expectedKeys"); return new MultimapBuilderWithKeys<@Nullable Object>() { @Override Map> createMap() { return Platform.newLinkedHashMapWithExpectedSize(expectedKeys); } }; } /** * Uses a naturally-ordered {@link TreeMap} to map keys to value collections. * *

The collections returned by {@link Multimap#keySet()}, {@link Multimap#keys()}, and {@link * Multimap#asMap()} will iterate through the keys in sorted order. * *

For all multimaps generated by the resulting builder, the {@link Multimap#keySet()} can be * safely cast to a {@link java.util.SortedSet}, and the {@link Multimap#asMap()} can safely be * cast to a {@link java.util.SortedMap}. */ @SuppressWarnings("rawtypes") public static MultimapBuilderWithKeys treeKeys() { return treeKeys(Ordering.natural()); } /** * Uses a {@link TreeMap} sorted by the specified comparator to map keys to value collections. * *

The collections returned by {@link Multimap#keySet()}, {@link Multimap#keys()}, and {@link * Multimap#asMap()} will iterate through the keys in sorted order. * *

For all multimaps generated by the resulting builder, the {@link Multimap#keySet()} can be * safely cast to a {@link java.util.SortedSet}, and the {@link Multimap#asMap()} can safely be * cast to a {@link java.util.SortedMap}. * *

Multimaps generated by the resulting builder will not be serializable if {@code comparator} * is not serializable. */ public static MultimapBuilderWithKeys treeKeys( Comparator comparator) { checkNotNull(comparator); return new MultimapBuilderWithKeys() { @Override Map> createMap() { return new TreeMap<>(comparator); } }; } /** * Uses an {@link EnumMap} to map keys to value collections. * * @since 16.0 */ public static > MultimapBuilderWithKeys enumKeys(Class keyClass) { checkNotNull(keyClass); return new MultimapBuilderWithKeys() { @SuppressWarnings("unchecked") @Override Map> createMap() { // K must actually be K0, since enums are effectively final // (their subclasses are inaccessible) return (Map>) new EnumMap>(keyClass); } }; } private static final class ArrayListSupplier implements Supplier>, Serializable { private final int expectedValuesPerKey; ArrayListSupplier(int expectedValuesPerKey) { this.expectedValuesPerKey = checkNonnegative(expectedValuesPerKey, "expectedValuesPerKey"); } @Override public List get() { return new ArrayList<>(expectedValuesPerKey); } } private enum LinkedListSupplier implements Supplier> { INSTANCE; public static Supplier> instance() { // Each call generates a fresh LinkedList, which can serve as a List for any V. @SuppressWarnings({"rawtypes", "unchecked"}) Supplier> result = (Supplier) INSTANCE; return result; } @Override public List get() { return new LinkedList<>(); } } private static final class HashSetSupplier implements Supplier>, Serializable { private final int expectedValuesPerKey; HashSetSupplier(int expectedValuesPerKey) { this.expectedValuesPerKey = checkNonnegative(expectedValuesPerKey, "expectedValuesPerKey"); } @Override public Set get() { return Platform.newHashSetWithExpectedSize(expectedValuesPerKey); } } private static final class LinkedHashSetSupplier implements Supplier>, Serializable { private final int expectedValuesPerKey; LinkedHashSetSupplier(int expectedValuesPerKey) { this.expectedValuesPerKey = checkNonnegative(expectedValuesPerKey, "expectedValuesPerKey"); } @Override public Set get() { return Platform.newLinkedHashSetWithExpectedSize(expectedValuesPerKey); } } private static final class TreeSetSupplier implements Supplier>, Serializable { private final Comparator comparator; TreeSetSupplier(Comparator comparator) { this.comparator = checkNotNull(comparator); } @Override public SortedSet get() { return new TreeSet<>(comparator); } } private static final class EnumSetSupplier> implements Supplier>, Serializable { private final Class clazz; EnumSetSupplier(Class clazz) { this.clazz = checkNotNull(clazz); } @Override public Set get() { return EnumSet.noneOf(clazz); } } /** * An intermediate stage in a {@link MultimapBuilder} in which the key-value collection map * implementation has been specified, but the value collection implementation has not. * * @param The upper bound on the key type of the generated multimap. * @since 16.0 */ public abstract static class MultimapBuilderWithKeys { private static final int DEFAULT_EXPECTED_VALUES_PER_KEY = 2; MultimapBuilderWithKeys() {} abstract Map> createMap(); /** Uses an {@link ArrayList} to store value collections. */ public ListMultimapBuilder arrayListValues() { return arrayListValues(DEFAULT_EXPECTED_VALUES_PER_KEY); } /** * Uses an {@link ArrayList} to store value collections, initialized to expect the specified * number of values per key. * * @throws IllegalArgumentException if {@code expectedValuesPerKey < 0} */ public ListMultimapBuilder arrayListValues(int expectedValuesPerKey) { checkNonnegative(expectedValuesPerKey, "expectedValuesPerKey"); return new ListMultimapBuilder() { @Override public ListMultimap build() { return Multimaps.newListMultimap( MultimapBuilderWithKeys.this.createMap(), new ArrayListSupplier(expectedValuesPerKey)); } }; } /** Uses a {@link LinkedList} to store value collections. */ public ListMultimapBuilder linkedListValues() { return new ListMultimapBuilder() { @Override public ListMultimap build() { return Multimaps.newListMultimap( MultimapBuilderWithKeys.this.createMap(), LinkedListSupplier.instance()); } }; } /** Uses a hash-based {@code Set} to store value collections. */ public SetMultimapBuilder hashSetValues() { return hashSetValues(DEFAULT_EXPECTED_VALUES_PER_KEY); } /** * Uses a hash-based {@code Set} to store value collections, initialized to expect the specified * number of values per key. * * @throws IllegalArgumentException if {@code expectedValuesPerKey < 0} */ public SetMultimapBuilder hashSetValues(int expectedValuesPerKey) { checkNonnegative(expectedValuesPerKey, "expectedValuesPerKey"); return new SetMultimapBuilder() { @Override public SetMultimap build() { return Multimaps.newSetMultimap( MultimapBuilderWithKeys.this.createMap(), new HashSetSupplier(expectedValuesPerKey)); } }; } /** Uses an insertion-ordered hash-based {@code Set} to store value collections. */ public SetMultimapBuilder linkedHashSetValues() { return linkedHashSetValues(DEFAULT_EXPECTED_VALUES_PER_KEY); } /** * Uses an insertion-ordered hash-based {@code Set} to store value collections, initialized to * expect the specified number of values per key. * * @throws IllegalArgumentException if {@code expectedValuesPerKey < 0} */ public SetMultimapBuilder linkedHashSetValues(int expectedValuesPerKey) { checkNonnegative(expectedValuesPerKey, "expectedValuesPerKey"); return new SetMultimapBuilder() { @Override public SetMultimap build() { return Multimaps.newSetMultimap( MultimapBuilderWithKeys.this.createMap(), new LinkedHashSetSupplier(expectedValuesPerKey)); } }; } /** Uses a naturally-ordered {@link TreeSet} to store value collections. */ @SuppressWarnings("rawtypes") public SortedSetMultimapBuilder treeSetValues() { return treeSetValues(Ordering.natural()); } /** * Uses a {@link TreeSet} ordered by the specified comparator to store value collections. * *

Multimaps generated by the resulting builder will not be serializable if {@code * comparator} is not serializable. */ public SortedSetMultimapBuilder treeSetValues( Comparator comparator) { checkNotNull(comparator, "comparator"); return new SortedSetMultimapBuilder() { @Override public SortedSetMultimap build() { return Multimaps.newSortedSetMultimap( MultimapBuilderWithKeys.this.createMap(), new TreeSetSupplier(comparator)); } }; } /** Uses an {@link EnumSet} to store value collections. */ public > SetMultimapBuilder enumSetValues(Class valueClass) { checkNotNull(valueClass, "valueClass"); return new SetMultimapBuilder() { @Override public SetMultimap build() { // V must actually be V0, since enums are effectively final // (their subclasses are inaccessible) @SuppressWarnings({"unchecked", "rawtypes"}) Supplier> factory = (Supplier) new EnumSetSupplier(valueClass); return Multimaps.newSetMultimap(MultimapBuilderWithKeys.this.createMap(), factory); } }; } } /** Returns a new, empty {@code Multimap} with the specified implementation. */ public abstract Multimap build(); /** * Returns a {@code Multimap} with the specified implementation, initialized with the entries of * {@code multimap}. */ public Multimap build( Multimap multimap) { Multimap result = build(); result.putAll(multimap); return result; } /** * A specialization of {@link MultimapBuilder} that generates {@link ListMultimap} instances. * * @since 16.0 */ public abstract static class ListMultimapBuilder< K0 extends @Nullable Object, V0 extends @Nullable Object> extends MultimapBuilder { ListMultimapBuilder() {} @Override public abstract ListMultimap build(); @Override public ListMultimap build( Multimap multimap) { return (ListMultimap) super.build(multimap); } } /** * A specialization of {@link MultimapBuilder} that generates {@link SetMultimap} instances. * * @since 16.0 */ public abstract static class SetMultimapBuilder< K0 extends @Nullable Object, V0 extends @Nullable Object> extends MultimapBuilder { SetMultimapBuilder() {} @Override public abstract SetMultimap build(); @Override public SetMultimap build( Multimap multimap) { return (SetMultimap) super.build(multimap); } } /** * A specialization of {@link MultimapBuilder} that generates {@link SortedSetMultimap} instances. * * @since 16.0 */ public abstract static class SortedSetMultimapBuilder< K0 extends @Nullable Object, V0 extends @Nullable Object> extends SetMultimapBuilder { SortedSetMultimapBuilder() {} @Override public abstract SortedSetMultimap build(); @Override public SortedSetMultimap build( Multimap multimap) { return (SortedSetMultimap) super.build(multimap); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy