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

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

/*
 * Copyright (C) 2007 Google Inc.
 *
 * 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 com.google.common.base.Nullable;
import static com.google.common.base.Preconditions.checkState;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * A convenient way to populate immutable Map instances, especially static-final
 * "constant Maps". Code such as
 *
 * 
 *   static final Map<String,Integer> ENGLISH_TO_INTEGER_MAP
 *       = createNumbersMap();
 *
 *   static Map<String,Integer> createNumbersMap() {
 *     Map<String,Integer> map = Maps.newHashMap();
 *     map.put("one", 1);
 *     map.put("two", 2);
 *     map.put("three", 3);
 *     return Collections.unmodifiableMap(map);
 *   }
 * 
* ... can be rewritten far more simply as ... *
 *   static final Map<String,Integer> ENGLISH_TO_INTEGER_MAP
 *     = new ImmutableMapBuilder<String,Integer>()
 *       .put("one", 1)
 *       .put("two", 2)
 *       .put("three", 3)
 *       .getMap();
 * 
* (Actually, for small immutable Maps, you can use members of the * even-more-convenient {@link Maps#immutableMap()} family of methods.) * * @author Kevin Bourrillion */ public class ImmutableMapBuilder { private ImmutableHashMap map; /** * Creates a new ImmutableMapBuilder populated with the contents of {@code * map}. */ public static ImmutableMapBuilder fromMap(Map map) { ImmutableMapBuilder builder = new ImmutableMapBuilder(map.size() * 3 / 2); for (Map.Entry entry : map.entrySet()) { builder.put(entry.getKey(), entry.getValue()); } return builder; } /** Creates a new ImmutableMapBuilder with an unspecified expected size. */ public ImmutableMapBuilder() { this(8); } /** * Creates a new ImmutableMapBuilder with the given expected size. * * @param expectedSize the approximate number of key-value pairs you expect * this map to contain */ public ImmutableMapBuilder(int expectedSize) { map = new ImmutableHashMap(expectedSize); } /** * Adds a key-value mapping to the map that will be returned by {@code * getMap}. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return this map builder (to enable call chaining) * @throws IllegalStateException if {@code getMap} has already been called */ public ImmutableMapBuilder put(@Nullable K key, @Nullable V value) { checkState(map != null, "map has already been created"); map.secretPut(key, value); return this; } /** * Returns a newly-created, immutable HashMap instance containing the keys and * values that were specified using {@code put}. * * @return a new, immutable HashMap instance * @throws IllegalStateException if {@code getMap} has already been called */ public Map getMap() { checkState(map != null, "map has already been created"); try { return map; } finally { map = null; } } private static class ImmutableHashMap extends HashMap { ImmutableHashMap(int expectedSize) { // avoid collisions by using 2-4x as many buckets as expected entries super(expectedSize * 2); } transient volatile Set keySet; @Override public Set keySet() { if (keySet == null) { keySet = Collections.unmodifiableSet(super.keySet()); } return keySet; } transient volatile Collection values; @Override public Collection values() { if (values == null) { values = Collections.unmodifiableCollection(super.values()); } return values; } transient volatile Set> entrySet; @Override public Set> entrySet() { if (entrySet == null) { entrySet = Maps.unmodifiableEntrySet(super.entrySet()); } return entrySet; } /* * This doesn't have to be volatile, for two reasons. Since Integer is * immutable, it's threadsafe. Multiple threads calculating the hash code * concurrently won't interfere with each other, and it's fine if one * overwrites the cachedHashCode generated by the other. */ transient Integer cachedHashCode; /* * This works because no one can call hashCode() until after all the calls * to secretPut() are finished. */ @Override public int hashCode() { if (cachedHashCode == null) { cachedHashCode = super.hashCode(); } return cachedHashCode; } private void secretPut(K key, V value) { super.put(key, value); } @Override public V put(K key, V value) { throw up(); } @Override public void putAll(Map m) { throw up(); } @Override public V remove(Object key) { throw up(); } @Override public void clear() { throw up(); } static UnsupportedOperationException up() { return new UnsupportedOperationException(); } private static final long serialVersionUID = -5187626034923451074L; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy