带有有界通配符的 Java Map.getOrDefault

MBo*_*rik 7 java generics

得到一个Map<String, ? extends Map<String, Integer>> mapOfMaps变量。

Map<String, Integer> result = mapOfMaps.get("aaa");
Run Code Online (Sandbox Code Playgroud)

有效,但是

Map<String, Integer> result = mapOfMaps.getOrDefault("aaa",Collections.emptyMap());
Run Code Online (Sandbox Code Playgroud)

类型 Map<String,capture#1-of ? 中的方法 getOrDefault(Object, capture#1-of ? extends Map<String,Integer>) extends Map<String,Integer>> 不适用于参数 (String, Map<String,Integer>)

同样适用于

Map<String, Integer> result = mapOfMaps.getOrDefault("aaa",Collections.<String,Integer>emptyMap());
Run Code Online (Sandbox Code Playgroud)

或者

Map<String, Integer> result = mapOfMaps.getOrDefault("aaa",(Map<String,Integer>)Collections.EMPTY_MAP);
Run Code Online (Sandbox Code Playgroud)

甚至

Map<String, Integer> result = mapOfMaps.getOrDefault("aaa",new HashMap<String, Integer>());
Run Code Online (Sandbox Code Playgroud)

有没有办法像这样使用 getOrDefault 或者我必须使用笨重的方式?

Map<String, Integer> result = mapOfMaps.get("aaa");
if( result == null ) {
  result = Collections.emptyMap();
}
Run Code Online (Sandbox Code Playgroud)

Izr*_*ruo 4

您可以使用Collections.unmodifiableMap来查看您的地图Map<String, Map<String, Integer>>

Map<String, ? extends Map<String, Integer>> mapOfMaps = new HashMap<>();
Map<String, Map<String, Integer>> view = Collections.unmodifiableMap(mapOfMaps);
Map<String, Integer> map = view.getOrDefault("foo", Collections.emptyMap());
Run Code Online (Sandbox Code Playgroud)

然而,在一行中,它看起来仍然很难看,因为您需要指定 的泛型类型参数unmodifiableMap

Map<String, Integer> map = Collections.<String, Map<String, Integer>>
    unmodifiableMap(mapOfMaps).getOrDefault("foo", Collections.emptyMap());
Run Code Online (Sandbox Code Playgroud)

解释

您不能调用任何具有无界或extends有界通配符参数的方法,因为通配符的确切类型在编译时未知。

让我们简化一下,看看Map<String, ? extends Number>,您可以将其中一个分配给

Map<String, ? extends Number> map = new HashMap<String, Integer>();
Map<String, ? extends Number> map = new HashMap<String, Double>();
Run Code Online (Sandbox Code Playgroud)

但是,当调用 时map.getOrDefault(Object k, V defaultValue),无法defaultValue在编译时确定 for 的类型,因为实际类型可能在运行时更改,即使对于完全相同的赋值(尽管不是相同的实例)也是如此。

// compile-time error, could require a Double or any other Number-type
Number i = map.getOrDefault("foo", (Number)Integer.MAX_VALUE);
Run Code Online (Sandbox Code Playgroud)