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.GwtCompatible; 20 21import java.util.Map; 22 23import javax.annotation.Nullable; 24 25/** 26 * Implementation of {@link ImmutableMap} with exactly one entry. 27 * 28 * @author Jesse Wilson 29 * @author Kevin Bourrillion 30 */ 31@GwtCompatible(serializable = true, emulated = true) 32@SuppressWarnings("serial") // uses writeReplace(), not default serialization 33final class SingletonImmutableMap<K, V> extends ImmutableMap<K, V> { 34 35 final transient K singleKey; 36 final transient V singleValue; 37 38 private transient Entry<K, V> entry; 39 40 SingletonImmutableMap(K singleKey, V singleValue) { 41 this.singleKey = singleKey; 42 this.singleValue = singleValue; 43 } 44 45 SingletonImmutableMap(Entry<K, V> entry) { 46 this.entry = entry; 47 this.singleKey = entry.getKey(); 48 this.singleValue = entry.getValue(); 49 } 50 51 private Entry<K, V> entry() { 52 Entry<K, V> e = entry; 53 return (e == null) 54 ? (entry = Maps.immutableEntry(singleKey, singleValue)) : e; 55 } 56 57 @Override public V get(@Nullable Object key) { 58 return singleKey.equals(key) ? singleValue : null; 59 } 60 61 @Override 62 public int size() { 63 return 1; 64 } 65 66 @Override public boolean isEmpty() { 67 return false; 68 } 69 70 @Override public boolean containsKey(@Nullable Object key) { 71 return singleKey.equals(key); 72 } 73 74 @Override public boolean containsValue(@Nullable Object value) { 75 return singleValue.equals(value); 76 } 77 78 @Override boolean isPartialView() { 79 return false; 80 } 81 82 private transient ImmutableSet<Entry<K, V>> entrySet; 83 84 @Override public ImmutableSet<Entry<K, V>> entrySet() { 85 ImmutableSet<Entry<K, V>> es = entrySet; 86 return (es == null) ? (entrySet = ImmutableSet.of(entry())) : es; 87 } 88 89 private transient ImmutableSet<K> keySet; 90 91 @Override public ImmutableSet<K> keySet() { 92 ImmutableSet<K> ks = keySet; 93 return (ks == null) ? (keySet = ImmutableSet.of(singleKey)) : ks; 94 } 95 96 private transient ImmutableCollection<V> values; 97 98 @Override public ImmutableCollection<V> values() { 99 ImmutableCollection<V> v = values; 100 return (v == null) ? (values = new Values<V>(singleValue)) : v; 101 } 102 103 @SuppressWarnings("serial") // uses writeReplace(), not default serialization 104 private static class Values<V> extends ImmutableCollection<V> { 105 final V singleValue; 106 107 Values(V singleValue) { 108 this.singleValue = singleValue; 109 } 110 111 @Override public boolean contains(Object object) { 112 return singleValue.equals(object); 113 } 114 115 @Override public boolean isEmpty() { 116 return false; 117 } 118 119 @Override 120 public int size() { 121 return 1; 122 } 123 124 @Override public UnmodifiableIterator<V> iterator() { 125 return Iterators.singletonIterator(singleValue); 126 } 127 128 @Override boolean isPartialView() { 129 return true; 130 } 131 } 132 133 @Override public boolean equals(@Nullable Object object) { 134 if (object == this) { 135 return true; 136 } 137 if (object instanceof Map) { 138 Map<?, ?> that = (Map<?, ?>) object; 139 if (that.size() != 1) { 140 return false; 141 } 142 Entry<?, ?> entry = that.entrySet().iterator().next(); 143 return singleKey.equals(entry.getKey()) 144 && singleValue.equals(entry.getValue()); 145 } 146 return false; 147 } 148 149 @Override public int hashCode() { 150 return singleKey.hashCode() ^ singleValue.hashCode(); 151 } 152 153 @Override public String toString() { 154 return new StringBuilder() 155 .append('{') 156 .append(singleKey.toString()) 157 .append('=') 158 .append(singleValue.toString()) 159 .append('}') 160 .toString(); 161 } 162} 163