我想在单个语句中声明一个完全填充的映射字段(可能包含几个嵌套语句),如下所示:
private static final Map<Integer,Boolean> map =
something-returning-an-unmodifiable-fully-populated-HashMap;
匿名初始化程序不会这样做,原因与调用返回新填充映射的函数不同:它们需要两个顶级语句:一个用于变量声明,一个用于方法或初始化程序
双花括号({{
和}}
)成语将起作用,但它会创建一个扩展HashMap<>
的全新类,我不喜欢这个代表的开销。
Java 8的lambdas是否可能提供更好的方法来实现这个目标?
答案 0 :(得分:9)
如果您想在一个语句中初始化Map
,可以使用Collectors.toMap
。
想象一下,你想构建一个Map<Integer, Boolean>
映射整数到调用某个函数f
的结果:
private static final Map<Integer,Boolean> MAP =
Collections.unmodifiableMap(IntStream.range(0, 1000)
.boxed()
.collect(Collectors.toMap(i -> i, i -> f(i))));
private static final boolean f(int i) {
return Math.random() * 100 > i;
}
如果你想用&#34;静态&#34;初始化它?已知值,如您的答案中的示例,您可以滥用Stream API,如下所示:
private static final Map<Integer, Boolean> MAP =
Stream.of(new Object[] { 1, false }, new Object[] { 2, true })
.collect(Collectors.toMap(s -> (int) s[0], s -> (boolean) s[1]));
请注意,这是一个真正的滥用,我个人永远不会使用它:如果你想构建一个具有已知静态值的Map,那么使用Streams并没有什么好处,你会更好关闭以使用静态初始化程序。
答案 1 :(得分:4)
如果您确实想在单个语句中初始化地图,可以编写自定义构建器并在项目中使用它。像这样:
public class MapBuilder<K, V> {
private final Map<K, V> map;
private MapBuilder(Map<K, V> map) {
this.map = map;
}
public MapBuilder<K, V> put(K key, V value) {
if(map == null)
throw new IllegalStateException();
map.put(key, value);
return this;
}
public MapBuilder<K, V> put(Map<? extends K, ? extends V> other) {
if(map == null)
throw new IllegalStateException();
map.putAll(other);
return this;
}
public Map<K, V> build() {
Map<K, V> m = map;
map = null;
return Collections.unmodifiableMap(m);
}
public static <K, V> MapBuilder<K, V> unordered() {
return new MapBuilder<>(new HashMap<>());
}
public static <K, V> MapBuilder<K, V> ordered() {
return new MapBuilder<>(new LinkedHashMap<>());
}
public static <K extends Comparable<K>, V> MapBuilder<K, V> sorted() {
return new MapBuilder<>(new TreeMap<>());
}
public static <K, V> MapBuilder<K, V> sorted(Comparator<K> comparator) {
return new MapBuilder<>(new TreeMap<>(comparator));
}
}
用法示例:
Map<Integer, Boolean> map = MapBuilder.<Integer, Boolean>unordered()
.put(1, true).put(2, false).build();
这也适用于Java-7。
作为旁注,我们可能会在Java-9中看到类似Map.of(1, true, 2, false)
的内容。有关详细信息,请参阅JDK-8048330。
答案 2 :(得分:2)
以下是如何使用lambda在单个语句中在Java 8中实现字段初始值设定项。
private static final Map<Integer,Boolean> map =
((Supplier<Map<Integer,Boolean>>)() -> {
Map<Integer,Boolean> mutableMap = new HashMap<>();
mutableMap.put( 1, false );
mutableMap.put( 2, true );
return Collections.unmodifiableMap( mutableMap );
}).get();
private static final Map<Integer,Boolean> map = Map.of( 1, false, 2, true );
如果您有超过10个条目,Map.of()
将无效,所以您需要:
private static final Map<Integer,Boolean> map = Map.ofEntries(
Map.entry( 1, false ),
Map.entry( 2, true ),
Map.entry( 3, false ),
Map.entry( 4, true ),
Map.entry( 5, false ),
Map.entry( 6, true ),
Map.entry( 7, false ),
Map.entry( 8, true ),
Map.entry( 9, false ),
Map.entry( 10, true ),
Map.entry( 11, false ) );
答案 3 :(得分:2)
Google Guava's Maps class为此提供了一些很好的实用方法。 此外,还有ImmutableMap class及其静态方法。 看看:
ImmutableMap.of(key1, value1, key2, value2, ...);
Maps.uniqueIndex(values, keyExtractor);
Maps.toMap(keys, valueMapper);