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

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

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * Copyright (C) 2008 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.checkEntryNotNull;
import static com.google.common.collect.Maps.immutableEntry;
import static java.util.Objects.requireNonNull;

import com.google.common.annotations.Beta;
import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;
import com.google.errorprone.annotations.CanIgnoreReturnValue;
import com.google.errorprone.annotations.DoNotCall;
import com.google.errorprone.annotations.DoNotMock;
import com.google.j2objc.annotations.Weak;
import com.google.j2objc.annotations.WeakOuter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Spliterator;
import java.util.function.BiConsumer;
import javax.annotation.CheckForNull;
import org.checkerframework.checker.nullness.qual.Nullable;

/**
 * A {@link Multimap} whose contents will never change, with many other important properties
 * detailed at {@link ImmutableCollection}.
 *
 * 

Warning: avoid direct usage of {@link ImmutableMultimap} as a type (as with * {@link Multimap} itself). Prefer subtypes such as {@link ImmutableSetMultimap} or {@link * ImmutableListMultimap}, which have well-defined {@link #equals} semantics, thus avoiding a common * source of bugs and confusion. * *

Note: every {@link ImmutableMultimap} offers an {@link #inverse} view, so there is no * need for a distinct {@code ImmutableBiMultimap} type. * *

* *

Key-grouped iteration. All view collections follow the same iteration order. In all * current implementations, the iteration order always keeps multiple entries with the same key * together. Any creation method that would customarily respect insertion order (such as {@link * #copyOf(Multimap)}) instead preserves key-grouped order by inserting entries for an existing key * immediately after the last entry having that key. * *

See the Guava User Guide article on immutable collections. * * @author Jared Levy * @since 2.0 */ @GwtCompatible(emulated = true) @ElementTypesAreNonnullByDefault public abstract class ImmutableMultimap extends BaseImmutableMultimap implements Serializable { /** * Returns an empty multimap. * *

Performance note: the instance returned is a singleton. */ public static ImmutableMultimap of() { return ImmutableListMultimap.of(); } /** Returns an immutable multimap containing a single entry. */ public static ImmutableMultimap of(K k1, V v1) { return ImmutableListMultimap.of(k1, v1); } /** Returns an immutable multimap containing the given entries, in order. */ public static ImmutableMultimap of(K k1, V v1, K k2, V v2) { return ImmutableListMultimap.of(k1, v1, k2, v2); } /** * Returns an immutable multimap containing the given entries, in the "key-grouped" insertion * order described in the class documentation. */ public static ImmutableMultimap of(K k1, V v1, K k2, V v2, K k3, V v3) { return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3); } /** * Returns an immutable multimap containing the given entries, in the "key-grouped" insertion * order described in the class documentation. */ public static ImmutableMultimap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4); } /** * Returns an immutable multimap containing the given entries, in the "key-grouped" insertion * order described in the class documentation. */ public static ImmutableMultimap of( K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { return ImmutableListMultimap.of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5); } // looking for of() with > 5 entries? Use the builder instead. /** * Returns a new builder. The generated builder is equivalent to the builder created by the {@link * Builder} constructor. */ public static Builder builder() { return new Builder<>(); } /** * A builder for creating immutable multimap instances, especially {@code public static final} * multimaps ("constant multimaps"). Example: * *

{@code
   * static final Multimap STRING_TO_INTEGER_MULTIMAP =
   *     new ImmutableMultimap.Builder()
   *         .put("one", 1)
   *         .putAll("several", 1, 2, 3)
   *         .putAll("many", 1, 2, 3, 4, 5)
   *         .build();
   * }
* *

Builder instances can be reused; it is safe to call {@link #build} multiple times to build * multiple multimaps in series. Each multimap contains the key-value mappings in the previously * created multimaps. * * @since 2.0 */ @DoNotMock public static class Builder { final Map> builderMap; @CheckForNull Comparator keyComparator; @CheckForNull Comparator valueComparator; /** * Creates a new builder. The returned builder is equivalent to the builder generated by {@link * ImmutableMultimap#builder}. */ public Builder() { this.builderMap = Platform.preservesInsertionOrderOnPutsMap(); } Collection newMutableValueCollection() { return new ArrayList<>(); } /** Adds a key-value mapping to the built multimap. */ @CanIgnoreReturnValue public Builder put(K key, V value) { checkEntryNotNull(key, value); Collection valueCollection = builderMap.get(key); if (valueCollection == null) { builderMap.put(key, valueCollection = newMutableValueCollection()); } valueCollection.add(value); return this; } /** * Adds an entry to the built multimap. * * @since 11.0 */ @CanIgnoreReturnValue public Builder put(Entry entry) { return put(entry.getKey(), entry.getValue()); } /** * Adds entries to the built multimap. * * @since 19.0 */ @CanIgnoreReturnValue @Beta public Builder putAll(Iterable> entries) { for (Entry entry : entries) { put(entry); } return this; } /** * Stores a collection of values with the same key in the built multimap. * * @throws NullPointerException if {@code key}, {@code values}, or any element in {@code values} * is null. The builder is left in an invalid state. */ @CanIgnoreReturnValue public Builder putAll(K key, Iterable values) { if (key == null) { throw new NullPointerException("null key in entry: null=" + Iterables.toString(values)); } Collection valueCollection = builderMap.get(key); if (valueCollection != null) { for (V value : values) { checkEntryNotNull(key, value); valueCollection.add(value); } return this; } Iterator valuesItr = values.iterator(); if (!valuesItr.hasNext()) { return this; } valueCollection = newMutableValueCollection(); while (valuesItr.hasNext()) { V value = valuesItr.next(); checkEntryNotNull(key, value); valueCollection.add(value); } builderMap.put(key, valueCollection); return this; } /** * Stores an array of values with the same key in the built multimap. * * @throws NullPointerException if the key or any value is null. The builder is left in an * invalid state. */ @CanIgnoreReturnValue public Builder putAll(K key, V... values) { return putAll(key, Arrays.asList(values)); } /** * Stores another multimap's entries in the built multimap. The generated multimap's key and * value orderings correspond to the iteration ordering of the {@code multimap.asMap()} view, * with new keys and values following any existing keys and values. * * @throws NullPointerException if any key or value in {@code multimap} is null. The builder is * left in an invalid state. */ @CanIgnoreReturnValue public Builder putAll(Multimap multimap) { for (Entry> entry : multimap.asMap().entrySet()) { putAll(entry.getKey(), entry.getValue()); } return this; } /** * Specifies the ordering of the generated multimap's keys. * * @since 8.0 */ @CanIgnoreReturnValue public Builder orderKeysBy(Comparator keyComparator) { this.keyComparator = checkNotNull(keyComparator); return this; } /** * Specifies the ordering of the generated multimap's values for each key. * * @since 8.0 */ @CanIgnoreReturnValue public Builder orderValuesBy(Comparator valueComparator) { this.valueComparator = checkNotNull(valueComparator); return this; } @CanIgnoreReturnValue Builder combine(Builder other) { for (Map.Entry> entry : other.builderMap.entrySet()) { putAll(entry.getKey(), entry.getValue()); } return this; } /** Returns a newly-created immutable multimap. */ public ImmutableMultimap build() { Collection>> mapEntries = builderMap.entrySet(); if (keyComparator != null) { mapEntries = Ordering.from(keyComparator).onKeys().immutableSortedCopy(mapEntries); } return ImmutableListMultimap.fromMapEntries(mapEntries, valueComparator); } } /** * Returns an immutable multimap containing the same mappings as {@code multimap}, in the * "key-grouped" iteration order described in the class documentation. * *

Despite the method name, this method attempts to avoid actually copying the data when it is * safe to do so. The exact circumstances under which a copy will or will not be performed are * undocumented and subject to change. * * @throws NullPointerException if any key or value in {@code multimap} is null */ public static ImmutableMultimap copyOf(Multimap multimap) { if (multimap instanceof ImmutableMultimap) { @SuppressWarnings("unchecked") // safe since multimap is not writable ImmutableMultimap kvMultimap = (ImmutableMultimap) multimap; if (!kvMultimap.isPartialView()) { return kvMultimap; } } return ImmutableListMultimap.copyOf(multimap); } /** * Returns an immutable multimap containing the specified entries. The returned multimap iterates * over keys in the order they were first encountered in the input, and the values for each key * are iterated in the order they were encountered. * * @throws NullPointerException if any key, value, or entry is null * @since 19.0 */ @Beta public static ImmutableMultimap copyOf( Iterable> entries) { return ImmutableListMultimap.copyOf(entries); } final transient ImmutableMap> map; final transient int size; // These constants allow the deserialization code to set final fields. This // holder class makes sure they are not initialized unless an instance is // deserialized. @GwtIncompatible // java serialization is not supported static class FieldSettersHolder { static final Serialization.FieldSetter MAP_FIELD_SETTER = Serialization.getFieldSetter(ImmutableMultimap.class, "map"); static final Serialization.FieldSetter SIZE_FIELD_SETTER = Serialization.getFieldSetter(ImmutableMultimap.class, "size"); } ImmutableMultimap(ImmutableMap> map, int size) { this.map = map; this.size = size; } // mutators (not supported) /** * Guaranteed to throw an exception and leave the multimap unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @CanIgnoreReturnValue @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") // DoNotCall wants this to be final, but we want to override it to return more specific types. // Inheritance is closed, and all subtypes are @DoNotCall, so this is safe to suppress. @SuppressWarnings("DoNotCall") public ImmutableCollection removeAll(@CheckForNull Object key) { throw new UnsupportedOperationException(); } /** * Guaranteed to throw an exception and leave the multimap unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @CanIgnoreReturnValue @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") // DoNotCall wants this to be final, but we want to override it to return more specific types. // Inheritance is closed, and all subtypes are @DoNotCall, so this is safe to suppress. @SuppressWarnings("DoNotCall") public ImmutableCollection replaceValues(K key, Iterable values) { throw new UnsupportedOperationException(); } /** * Guaranteed to throw an exception and leave the multimap unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") public final void clear() { throw new UnsupportedOperationException(); } /** * Returns an immutable collection of the values for the given key. If no mappings in the multimap * have the provided key, an empty immutable collection is returned. The values are in the same * order as the parameters used to build this multimap. */ @Override public abstract ImmutableCollection get(K key); /** * Returns an immutable multimap which is the inverse of this one. For every key-value mapping in * the original, the result will have a mapping with key and value reversed. * * @since 11.0 */ public abstract ImmutableMultimap inverse(); /** * Guaranteed to throw an exception and leave the multimap unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @CanIgnoreReturnValue @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") public final boolean put(K key, V value) { throw new UnsupportedOperationException(); } /** * Guaranteed to throw an exception and leave the multimap unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @CanIgnoreReturnValue @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") public final boolean putAll(K key, Iterable values) { throw new UnsupportedOperationException(); } /** * Guaranteed to throw an exception and leave the multimap unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @CanIgnoreReturnValue @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") public final boolean putAll(Multimap multimap) { throw new UnsupportedOperationException(); } /** * Guaranteed to throw an exception and leave the multimap unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @CanIgnoreReturnValue @Deprecated @Override @DoNotCall("Always throws UnsupportedOperationException") public final boolean remove(@CheckForNull Object key, @CheckForNull Object value) { throw new UnsupportedOperationException(); } /** * Returns {@code true} if this immutable multimap's implementation contains references to * user-created objects that aren't accessible via this multimap's methods. This is generally used * to determine whether {@code copyOf} implementations should make an explicit copy to avoid * memory leaks. */ boolean isPartialView() { return map.isPartialView(); } // accessors @Override public boolean containsKey(@CheckForNull Object key) { return map.containsKey(key); } @Override public boolean containsValue(@CheckForNull Object value) { return value != null && super.containsValue(value); } @Override public int size() { return size; } // views /** * Returns an immutable set of the distinct keys in this multimap, in the same order as they * appear in this multimap. */ @Override public ImmutableSet keySet() { return map.keySet(); } @Override Set createKeySet() { throw new AssertionError("unreachable"); } /** * Returns an immutable map that associates each key with its corresponding values in the * multimap. Keys and values appear in the same order as in this multimap. */ @Override @SuppressWarnings("unchecked") // a widening cast public ImmutableMap> asMap() { return (ImmutableMap) map; } @Override Map> createAsMap() { throw new AssertionError("should never be called"); } /** Returns an immutable collection of all key-value pairs in the multimap. */ @Override public ImmutableCollection> entries() { return (ImmutableCollection>) super.entries(); } @Override ImmutableCollection> createEntries() { return new EntryCollection<>(this); } private static class EntryCollection extends ImmutableCollection> { @Weak final ImmutableMultimap multimap; EntryCollection(ImmutableMultimap multimap) { this.multimap = multimap; } @Override public UnmodifiableIterator> iterator() { return multimap.entryIterator(); } @Override boolean isPartialView() { return multimap.isPartialView(); } @Override public int size() { return multimap.size(); } @Override public boolean contains(@CheckForNull Object object) { if (object instanceof Entry) { Entry entry = (Entry) object; return multimap.containsEntry(entry.getKey(), entry.getValue()); } return false; } private static final long serialVersionUID = 0; } @Override UnmodifiableIterator> entryIterator() { return new UnmodifiableIterator>() { final Iterator>> asMapItr = map.entrySet().iterator(); @CheckForNull K currentKey = null; Iterator valueItr = Iterators.emptyIterator(); @Override public boolean hasNext() { return valueItr.hasNext() || asMapItr.hasNext(); } @Override public Entry next() { if (!valueItr.hasNext()) { Entry> entry = asMapItr.next(); currentKey = entry.getKey(); valueItr = entry.getValue().iterator(); } /* * requireNonNull is safe: The first call to this method always enters the !hasNext() case * and populates currentKey, after which it's never cleared. */ return immutableEntry(requireNonNull(currentKey), valueItr.next()); } }; } @Override Spliterator> entrySpliterator() { return CollectSpliterators.flatMap( asMap().entrySet().spliterator(), keyToValueCollectionEntry -> { K key = keyToValueCollectionEntry.getKey(); Collection valueCollection = keyToValueCollectionEntry.getValue(); return CollectSpliterators.map( valueCollection.spliterator(), (V value) -> Maps.immutableEntry(key, value)); }, Spliterator.SIZED | (this instanceof SetMultimap ? Spliterator.DISTINCT : 0), size()); } @Override public void forEach(BiConsumer action) { checkNotNull(action); asMap() .forEach( (key, valueCollection) -> valueCollection.forEach(value -> action.accept(key, value))); } /** * Returns an immutable multiset containing all the keys in this multimap, in the same order and * with the same frequencies as they appear in this multimap; to get only a single occurrence of * each key, use {@link #keySet}. */ @Override public ImmutableMultiset keys() { return (ImmutableMultiset) super.keys(); } @Override ImmutableMultiset createKeys() { return new Keys(); } @SuppressWarnings("serial") // Uses writeReplace, not default serialization @WeakOuter class Keys extends ImmutableMultiset { @Override public boolean contains(@CheckForNull Object object) { return containsKey(object); } @Override public int count(@CheckForNull Object element) { Collection values = map.get(element); return (values == null) ? 0 : values.size(); } @Override public ImmutableSet elementSet() { return keySet(); } @Override public int size() { return ImmutableMultimap.this.size(); } @Override Multiset.Entry getEntry(int index) { Map.Entry> entry = map.entrySet().asList().get(index); return Multisets.immutableEntry(entry.getKey(), entry.getValue().size()); } @Override boolean isPartialView() { return true; } @GwtIncompatible @Override Object writeReplace() { return new KeysSerializedForm(ImmutableMultimap.this); } } @GwtIncompatible private static final class KeysSerializedForm implements Serializable { final ImmutableMultimap multimap; KeysSerializedForm(ImmutableMultimap multimap) { this.multimap = multimap; } Object readResolve() { return multimap.keys(); } } /** * Returns an immutable collection of the values in this multimap. Its iterator traverses the * values for the first key, the values for the second key, and so on. */ @Override public ImmutableCollection values() { return (ImmutableCollection) super.values(); } @Override ImmutableCollection createValues() { return new Values<>(this); } @Override UnmodifiableIterator valueIterator() { return new UnmodifiableIterator() { Iterator> valueCollectionItr = map.values().iterator(); Iterator valueItr = Iterators.emptyIterator(); @Override public boolean hasNext() { return valueItr.hasNext() || valueCollectionItr.hasNext(); } @Override public V next() { if (!valueItr.hasNext()) { valueItr = valueCollectionItr.next().iterator(); } return valueItr.next(); } }; } private static final class Values extends ImmutableCollection { @Weak private final transient ImmutableMultimap multimap; Values(ImmutableMultimap multimap) { this.multimap = multimap; } @Override public boolean contains(@CheckForNull Object object) { return multimap.containsValue(object); } @Override public UnmodifiableIterator iterator() { return multimap.valueIterator(); } @GwtIncompatible // not present in emulated superclass @Override int copyIntoArray(@Nullable Object[] dst, int offset) { for (ImmutableCollection valueCollection : multimap.map.values()) { offset = valueCollection.copyIntoArray(dst, offset); } return offset; } @Override public int size() { return multimap.size(); } @Override boolean isPartialView() { return true; } private static final long serialVersionUID = 0; } private static final long serialVersionUID = 0; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy