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 Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging 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: 35.0.0.Beta1
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 com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.GwtIncompatible;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.Nullable;

/**
 * An immutable {@link Multimap}. Does not permit null keys or values.
 *
 * 

Unlike {@link Multimaps#unmodifiableMultimap(Multimap)}, which is * a view of a separate multimap which can still change, an instance of * {@code ImmutableMultimap} contains its own data and will never * change. {@code ImmutableMultimap} is convenient for * {@code public static final} multimaps ("constant multimaps") and also lets * you easily make a "defensive copy" of a multimap provided to your class by * a caller. * *

Note: Although this class is not final, it cannot be subclassed as * it has no public or protected constructors. Thus, instances of this class * are guaranteed to be immutable. * *

In addition to methods defined by {@link Multimap}, an {@link #inverse} * method is also supported. * *

See the Guava User Guide article on * immutable collections. * * @author Jared Levy * @since 2.0 (imported from Google Collections Library) */ @GwtCompatible(emulated = true) public abstract class ImmutableMultimap extends AbstractMultimap implements Serializable { /** Returns an empty multimap. */ 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 order. */ 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 order. */ 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 order. */ 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(); } /** * Multimap for {@link ImmutableMultimap.Builder} that maintains key and * value orderings, allows duplicate values, and performs better than * {@link LinkedListMultimap}. */ private static class BuilderMultimap extends AbstractMapBasedMultimap { BuilderMultimap() { super(new LinkedHashMap>()); } @Override Collection createCollection() { return Lists.newArrayList(); } private static final long serialVersionUID = 0; } /** * 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 (imported from Google Collections Library) */ public static class Builder { Multimap builderMultimap = new BuilderMultimap(); Comparator keyComparator; Comparator valueComparator; /** * Creates a new builder. The returned builder is equivalent to the builder * generated by {@link ImmutableMultimap#builder}. */ public Builder() {} /** * Adds a key-value mapping to the built multimap. */ public Builder put(K key, V value) { checkEntryNotNull(key, value); builderMultimap.put(key, value); return this; } /** * Adds an entry to the built multimap. * * @since 11.0 */ public Builder put(Entry entry) { return put(entry.getKey(), entry.getValue()); } /** * 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. */ public Builder putAll(K key, Iterable values) { if (key == null) { throw new NullPointerException( "null key in entry: null=" + Iterables.toString(values)); } Collection valueList = builderMultimap.get(key); for (V value : values) { checkEntryNotNull(key, value); valueList.add(value); } 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. */ 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. */ 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 */ 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 */ public Builder orderValuesBy(Comparator valueComparator) { this.valueComparator = checkNotNull(valueComparator); return this; } /** * Returns a newly-created immutable multimap. */ public ImmutableMultimap build() { if (valueComparator != null) { for (Collection values : builderMultimap.asMap().values()) { List list = (List ) values; Collections.sort(list, valueComparator); } } if (keyComparator != null) { Multimap sortedCopy = new BuilderMultimap(); List>> entries = Lists.newArrayList( builderMultimap.asMap().entrySet()); Collections.sort( entries, Ordering.from(keyComparator).onKeys()); for (Map.Entry> entry : entries) { sortedCopy.putAll(entry.getKey(), entry.getValue()); } builderMultimap = sortedCopy; } return copyOf(builderMultimap); } } /** * Returns an immutable multimap containing the same mappings as {@code * multimap}. The generated multimap's key and value orderings correspond to * the iteration ordering of the {@code multimap.asMap()} view. * *

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); } 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"); static final Serialization.FieldSetter EMPTY_SET_FIELD_SETTER = Serialization.getFieldSetter( ImmutableSetMultimap.class, "emptySet"); } 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. */ @Deprecated @Override public ImmutableCollection removeAll(Object key) { throw new UnsupportedOperationException(); } /** * Guaranteed to throw an exception and leave the multimap unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @Deprecated @Override 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 public 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. */ @Deprecated @Override public 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. */ @Deprecated @Override public 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. */ @Deprecated @Override public boolean putAll(Multimap multimap) { throw new UnsupportedOperationException(); } /** * Guaranteed to throw an exception and leave the multimap unmodified. * * @throws UnsupportedOperationException always * @deprecated Unsupported operation. */ @Deprecated @Override public boolean remove(Object key, 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(@Nullable Object key) { return map.containsKey(key); } @Override public boolean containsValue(@Nullable 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. These keys * are ordered according to when they first appeared during the construction * of this multimap. */ @Override public ImmutableSet keySet() { return map.keySet(); } /** * Returns an immutable map that associates each key with its corresponding * values in the 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. Its * iterator traverses the values for the first key, the values for the second * key, and so on. */ @Override public ImmutableCollection> entries() { return (ImmutableCollection>) super.entries(); } @Override ImmutableCollection> createEntries() { return new EntryCollection(this); } private static class EntryCollection extends ImmutableCollection> { 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(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; } private abstract class Itr extends UnmodifiableIterator { final Iterator>> mapIterator = asMap().entrySet().iterator(); K key = null; Iterator valueIterator = Iterators.emptyIterator(); abstract T output(K key, V value); @Override public boolean hasNext() { return mapIterator.hasNext() || valueIterator.hasNext(); } @Override public T next() { if (!valueIterator.hasNext()) { Entry> mapEntry = mapIterator.next(); key = mapEntry.getKey(); valueIterator = mapEntry.getValue().iterator(); } return output(key, valueIterator.next()); } } @Override UnmodifiableIterator> entryIterator() { return new Itr>() { @Override Entry output(K key, V value) { return Maps.immutableEntry(key, value); } }; } /** * Returns a collection, which may contain duplicates, of all keys. The number * of times a key appears in the returned multiset equals the number of * mappings the key has in the multimap. Duplicate keys appear consecutively * in the multiset's iteration order. */ @Override public ImmutableMultiset keys() { return (ImmutableMultiset) super.keys(); } @Override ImmutableMultiset createKeys() { return new Keys(); } @SuppressWarnings("serial") // Uses writeReplace, not default serialization class Keys extends ImmutableMultiset { @Override public boolean contains(@Nullable Object object) { return containsKey(object); } @Override public int count(@Nullable Object element) { Collection values = map.get(element); return (values == null) ? 0 : values.size(); } @Override public Set 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; } } /** * 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 Itr() { @Override V output(K key, V value) { return value; } }; } private static final class Values extends ImmutableCollection { private transient final ImmutableMultimap multimap; Values(ImmutableMultimap multimap) { this.multimap = multimap; } @Override public boolean contains(@Nullable Object object) { return multimap.containsValue(object); } @Override public UnmodifiableIterator iterator() { return multimap.valueIterator(); } @GwtIncompatible("not present in emulated superclass") @Override int copyIntoArray(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 - 2025 Weber Informatics LLC | Privacy Policy