ImmutableListMultimap.java revision 1d580d0f6ee4f21eb309ba7b509d2c6d671c4044
1/* 2 * Copyright (C) 2008 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.common.collect; 18 19import com.google.common.annotations.Beta; 20import com.google.common.annotations.GwtCompatible; 21 22import java.util.Collection; 23import java.util.Comparator; 24import java.util.Map.Entry; 25 26import javax.annotation.Nullable; 27 28/** 29 * An immutable {@link ListMultimap} with reliable user-specified key and value 30 * iteration order. Does not permit null keys or values. 31 * 32 * <p>Unlike {@link Multimaps#unmodifiableListMultimap(ListMultimap)}, which is 33 * a <i>view</i> of a separate multimap which can still change, an instance of 34 * {@code ImmutableListMultimap} contains its own data and will <i>never</i> 35 * change. {@code ImmutableListMultimap} is convenient for 36 * {@code public static final} multimaps ("constant multimaps") and also lets 37 * you easily make a "defensive copy" of a multimap provided to your class by 38 * a caller. 39 * 40 * <p><b>Note:</b> Although this class is not final, it cannot be subclassed as 41 * it has no public or protected constructors. Thus, instances of this class 42 * are guaranteed to be immutable. 43 * 44 * @author Jared Levy 45 * @since 2.0 (imported from Google Collections Library) 46 */ 47@GwtCompatible(serializable = true, emulated = true) 48public class ImmutableListMultimap<K, V> 49 extends ImmutableMultimap<K, V> 50 implements ListMultimap<K, V> { 51 52 /** Returns the empty multimap. */ 53 // Casting is safe because the multimap will never hold any elements. 54 @SuppressWarnings("unchecked") 55 public static <K, V> ImmutableListMultimap<K, V> of() { 56 return (ImmutableListMultimap<K, V>) EmptyImmutableListMultimap.INSTANCE; 57 } 58 59 /** 60 * Returns an immutable multimap containing a single entry. 61 */ 62 public static <K, V> ImmutableListMultimap<K, V> of(K k1, V v1) { 63 ImmutableListMultimap.Builder<K, V> builder 64 = ImmutableListMultimap.builder(); 65 builder.put(k1, v1); 66 return builder.build(); 67 } 68 69 /** 70 * Returns an immutable multimap containing the given entries, in order. 71 */ 72 public static <K, V> ImmutableListMultimap<K, V> of(K k1, V v1, K k2, V v2) { 73 ImmutableListMultimap.Builder<K, V> builder 74 = ImmutableListMultimap.builder(); 75 builder.put(k1, v1); 76 builder.put(k2, v2); 77 return builder.build(); 78 } 79 80 /** 81 * Returns an immutable multimap containing the given entries, in order. 82 */ 83 public static <K, V> ImmutableListMultimap<K, V> of( 84 K k1, V v1, K k2, V v2, K k3, V v3) { 85 ImmutableListMultimap.Builder<K, V> builder 86 = ImmutableListMultimap.builder(); 87 builder.put(k1, v1); 88 builder.put(k2, v2); 89 builder.put(k3, v3); 90 return builder.build(); 91 } 92 93 /** 94 * Returns an immutable multimap containing the given entries, in order. 95 */ 96 public static <K, V> ImmutableListMultimap<K, V> of( 97 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) { 98 ImmutableListMultimap.Builder<K, V> builder 99 = ImmutableListMultimap.builder(); 100 builder.put(k1, v1); 101 builder.put(k2, v2); 102 builder.put(k3, v3); 103 builder.put(k4, v4); 104 return builder.build(); 105 } 106 107 /** 108 * Returns an immutable multimap containing the given entries, in order. 109 */ 110 public static <K, V> ImmutableListMultimap<K, V> of( 111 K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) { 112 ImmutableListMultimap.Builder<K, V> builder 113 = ImmutableListMultimap.builder(); 114 builder.put(k1, v1); 115 builder.put(k2, v2); 116 builder.put(k3, v3); 117 builder.put(k4, v4); 118 builder.put(k5, v5); 119 return builder.build(); 120 } 121 122 // looking for of() with > 5 entries? Use the builder instead. 123 124 /** 125 * Returns a new builder. The generated builder is equivalent to the builder 126 * created by the {@link Builder} constructor. 127 */ 128 public static <K, V> Builder<K, V> builder() { 129 return new Builder<K, V>(); 130 } 131 132 /** 133 * A builder for creating immutable {@code ListMultimap} instances, especially 134 * {@code public static final} multimaps ("constant multimaps"). Example: 135 * <pre> {@code 136 * 137 * static final Multimap<String, Integer> STRING_TO_INTEGER_MULTIMAP = 138 * new ImmutableListMultimap.Builder<String, Integer>() 139 * .put("one", 1) 140 * .putAll("several", 1, 2, 3) 141 * .putAll("many", 1, 2, 3, 4, 5) 142 * .build();}</pre> 143 * 144 * Builder instances can be reused; it is safe to call {@link #build} multiple 145 * times to build multiple multimaps in series. Each multimap contains the 146 * key-value mappings in the previously created multimaps. 147 * 148 * @since 2.0 (imported from Google Collections Library) 149 */ 150 public static final class Builder<K, V> 151 extends ImmutableMultimap.Builder<K, V> { 152 /** 153 * Creates a new builder. The returned builder is equivalent to the builder 154 * generated by {@link ImmutableListMultimap#builder}. 155 */ 156 public Builder() {} 157 158 @Override public Builder<K, V> put(K key, V value) { 159 super.put(key, value); 160 return this; 161 } 162 163 /** 164 * {@inheritDoc} 165 * 166 * @since 11.0 167 */ 168 @Override public Builder<K, V> put( 169 Entry<? extends K, ? extends V> entry) { 170 super.put(entry); 171 return this; 172 } 173 174 @Override public Builder<K, V> putAll(K key, Iterable<? extends V> values) { 175 super.putAll(key, values); 176 return this; 177 } 178 179 @Override public Builder<K, V> putAll(K key, V... values) { 180 super.putAll(key, values); 181 return this; 182 } 183 184 @Override public Builder<K, V> putAll( 185 Multimap<? extends K, ? extends V> multimap) { 186 super.putAll(multimap); 187 return this; 188 } 189 190 /** 191 * {@inheritDoc} 192 * 193 * @since 8.0 194 */ 195 @Beta @Override 196 public Builder<K, V> orderKeysBy(Comparator<? super K> keyComparator) { 197 super.orderKeysBy(keyComparator); 198 return this; 199 } 200 201 /** 202 * {@inheritDoc} 203 * 204 * @since 8.0 205 */ 206 @Beta @Override 207 public Builder<K, V> orderValuesBy(Comparator<? super V> valueComparator) { 208 super.orderValuesBy(valueComparator); 209 return this; 210 } 211 212 /** 213 * Returns a newly-created immutable list multimap. 214 */ 215 @Override public ImmutableListMultimap<K, V> build() { 216 return (ImmutableListMultimap<K, V>) super.build(); 217 } 218 } 219 220 /** 221 * Returns an immutable multimap containing the same mappings as {@code 222 * multimap}. The generated multimap's key and value orderings correspond to 223 * the iteration ordering of the {@code multimap.asMap()} view. 224 * 225 * <p>Despite the method name, this method attempts to avoid actually copying 226 * the data when it is safe to do so. The exact circumstances under which a 227 * copy will or will not be performed are undocumented and subject to change. 228 * 229 * @throws NullPointerException if any key or value in {@code multimap} is 230 * null 231 */ 232 public static <K, V> ImmutableListMultimap<K, V> copyOf( 233 Multimap<? extends K, ? extends V> multimap) { 234 if (multimap.isEmpty()) { 235 return of(); 236 } 237 238 // TODO(user): copy ImmutableSetMultimap by using asList() on the sets 239 if (multimap instanceof ImmutableListMultimap) { 240 @SuppressWarnings("unchecked") // safe since multimap is not writable 241 ImmutableListMultimap<K, V> kvMultimap 242 = (ImmutableListMultimap<K, V>) multimap; 243 if (!kvMultimap.isPartialView()) { 244 return kvMultimap; 245 } 246 } 247 248 ImmutableMap.Builder<K, ImmutableList<V>> builder = ImmutableMap.builder(); 249 int size = 0; 250 251 for (Entry<? extends K, ? extends Collection<? extends V>> entry 252 : multimap.asMap().entrySet()) { 253 ImmutableList<V> list = ImmutableList.copyOf(entry.getValue()); 254 if (!list.isEmpty()) { 255 builder.put(entry.getKey(), list); 256 size += list.size(); 257 } 258 } 259 260 return new ImmutableListMultimap<K, V>(builder.build(), size); 261 } 262 263 ImmutableListMultimap(ImmutableMap<K, ImmutableList<V>> map, int size) { 264 super(map, size); 265 } 266 267 // views 268 269 /** 270 * Returns an immutable list of the values for the given key. If no mappings 271 * in the multimap have the provided key, an empty immutable list is 272 * returned. The values are in the same order as the parameters used to build 273 * this multimap. 274 */ 275 @Override public ImmutableList<V> get(@Nullable K key) { 276 // This cast is safe as its type is known in constructor. 277 ImmutableList<V> list = (ImmutableList<V>) map.get(key); 278 return (list == null) ? ImmutableList.<V>of() : list; 279 } 280 281 private transient ImmutableListMultimap<V, K> inverse; 282 283 /** 284 * {@inheritDoc} 285 * 286 * <p>Because an inverse of a list multimap can contain multiple pairs with the same key and 287 * value, this method returns an {@code ImmutableListMultimap} rather than the 288 * {@code ImmutableMultimap} specified in the {@code ImmutableMultimap} class. 289 * 290 * @since 11 291 */ 292 @Beta 293 public ImmutableListMultimap<V, K> inverse() { 294 ImmutableListMultimap<V, K> result = inverse; 295 return (result == null) ? (inverse = invert()) : result; 296 } 297 298 private ImmutableListMultimap<V, K> invert() { 299 Builder<V, K> builder = builder(); 300 for (Entry<K, V> entry : entries()) { 301 builder.put(entry.getValue(), entry.getKey()); 302 } 303 ImmutableListMultimap<V, K> invertedMultimap = builder.build(); 304 invertedMultimap.inverse = this; 305 return invertedMultimap; 306 } 307 308 /** 309 * Guaranteed to throw an exception and leave the multimap unmodified. 310 * 311 * @throws UnsupportedOperationException always 312 */ 313 @Override public ImmutableList<V> removeAll(Object key) { 314 throw new UnsupportedOperationException(); 315 } 316 317 /** 318 * Guaranteed to throw an exception and leave the multimap unmodified. 319 * 320 * @throws UnsupportedOperationException always 321 */ 322 @Override public ImmutableList<V> replaceValues( 323 K key, Iterable<? extends V> values) { 324 throw new UnsupportedOperationException(); 325 } 326} 327