如何使用lambda初始化地图?

我想在单个语句中声明一个完全填充的映射字段(可能包含几个嵌套语句),如下所示:

private static final Map map = something-returning-an-unmodifiable-fully-populated-HashMap; 

匿名初始化程序不会这样做,因为调用返回新填充映射的函数不会这样做:它们需要两个顶级语句:一个用于变量声明,一个用于方法或初始化程序。

双花括号( {{}} )成语将起作用,但它会创建一个扩展HashMap全新类,我不喜欢这个代表的开销。

Java 8的lambdas是否可能提供更好的方法来实现这一目标?

如果要在单个语句中初始化Map ,可以使用Collectors.toMap

想象一下,你想构建一个Map将整数映射到调用某个函数f的结果:

 private static final Map 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; } 

如果您想使用“静态”已知值对其进行初始化,例如答案中的示例,则可以滥用Stream API,如下所示:

 private static final Map MAP = Stream.of(new Object[] { 1, false }, new Object[] { 2, true }) .collect(Collectors.toMap(s -> (int) s[0], s -> (boolean) s[1])); 

请注意,这是一个真正的滥用 ,我个人永远不会使用它:如果你想构建一个具有已知静态值的Map,使用Streams没有任何好处,你最好使用静态初始化器。

如果您确实想在单个语句中初始化映射,则可以编写自定义构建器并在项目中使用它。 像这样的东西:

 public class MapBuilder { private final Map map; private MapBuilder(Map map) { this.map = map; } public MapBuilder put(K key, V value) { if(map == null) throw new IllegalStateException(); map.put(key, value); return this; } public MapBuilder put(Map other) { if(map == null) throw new IllegalStateException(); map.putAll(other); return this; } public Map build() { Map m = map; map = null; return Collections.unmodifiableMap(m); } public static  MapBuilder unordered() { return new MapBuilder<>(new HashMap<>()); } public static  MapBuilder ordered() { return new MapBuilder<>(new LinkedHashMap<>()); } public static , V> MapBuilder sorted() { return new MapBuilder<>(new TreeMap<>()); } public static  MapBuilder sorted(Comparator comparator) { return new MapBuilder<>(new TreeMap<>(comparator)); } } 

用法示例:

 Map map = MapBuilder.unordered() .put(1, true).put(2, false).build(); 

这也适用于Java-7。

作为旁注,我们可能会在Java-9中看到类似Map.of(1, true, 2, false) 。 有关详细信息,请参阅JDK-8048330 。

Google Guava的Maps类为此提供了一些很好的实用方法。 此外,还有ImmutableMap类及其静态方法。 看一下:

  ImmutableMap.of(key1, value1, key2, value2, ...); Maps.uniqueIndex(values, keyExtractor); Maps.toMap(keys, valueMapper); 

以下是如何使用lambda在单个语句中在Java 8中实现字段初始值设定项。

 private static final Map map = ((Supplier>)() -> { Map mutableMap = new HashMap<>(); mutableMap.put( 1, false ); mutableMap.put( 2, true ); return Collections.unmodifiableMap( mutableMap ); }).get(); 

Java 9解决方案:

 private static final Map map = Map.of( 1, false, 2, true ); 

如果你有超过10个条目, Map.of()将无法工作,所以你需要这个:

 private static final Map 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 ) );