泛型类型推断不适用于方法链接?

2022-09-01 12:04:57

此代码在 Java 8 中编译,但在 Java 7 中编译失败:

class Map<K,V> {
    static <K,V> Map<K,V> empty() {return null;}
    Map<K,V> put(K k, V v) {return null;}
    V get(K k) {return null;}
}

class A {
    static void f(Map<Integer,String> m){}
    public static void main(String[] args) {
        f(Map.empty());
    }
}

它没有推断出从以下位置返回的具体类型:MapMap.empty()

$ javac7 A.java
A.java:10: error: method f in class A cannot be applied to given types;
        f(Map.empty());
        ^
  required: Map<Integer,String>
  found: Map<Object,Object>
  reason: actual argument Map<Object,Object> cannot be converted to Map<Integer,String> by method invocation conversion
1 error

如果将调用更改为 ,则会编译。在Java 8中,它无需诉诸于此即可工作。ff(Map.<Integer,String>empty());

但是,如果将调用更改为 ,则无法在 Java 7 和 8 上再次编译。为什么?ff(Map.empty().put(1,"A").put(2,"B"));

$ $javac7 A.java 
A.java:10: error: method f in class A cannot be applied to given types;
        f(Map.empty().put(1,"A").put(2,"B"));
        ^
  required: Map<Integer,String>
  found: Map<Object,Object>
  reason: actual argument Map<Object,Object> cannot be converted to Map<Integer,String> by method invocation conversion
1 error

$ $javac8 A.java
A.java:10: error: incompatible types: Map<Object,Object> cannot be converted to Map<Integer,String>
        f(Map.empty().put(1,"A").put(2,"B"));
                                    ^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error

$ $javac8 -Xdiags:verbose A.java
A.java:10: error: method f in class A cannot be applied to given types;
        f(Map.empty().put(1,"A").put(2,"B"));
        ^
  required: Map<Integer,String>
  found: Map<Object,Object>
  reason: argument mismatch; Map<Object,Object> cannot be converted to Map<Integer,String>
1 error

答案 1

为什么?

因为泛型类型的类型推断尚未扩展到链式调用。

泛型类型推理的 java 教程中

什么是目标类型的概念已扩展为包括方法参数。

这就是为什么这个代码:

f(Map.empty());

编译。

但这段代码没有,因为这是一个链式调用:

f(Map.empty().put(1,"A").put(2,"B"));

您还可以在用于评估的 JavaTM 编程语言最终发行版的 JSR-000335 Lambda 表达式(特别是 D 部分)中找到一小段内容:

在允许推断“链”方面有一些兴趣:在a().b()中,将类型信息从b的调用传递到a的调用。这为推理算法的复杂性增加了另一个维度,因为部分信息必须在两个方向上传递;仅当所有实例化(例如 List)的返回类型被固定时,它才有效。此功能不能很好地适应 poly 表达式模型,因为目标类型不容易派生。但也许通过额外的增强功能,将来可以添加它。

所以也许在Java 9中。


答案 2

Map.Entry.comparingByValue().reversed()的类型是什么?- 只是为了回答这个问题更简单。

unSortedMap.entrySet().stream()
                    .filter(e -> e.getValue() > 1)
                    .sorted(Entry.comparingByValue(Comparator.reverseOrder()))
                    .collect(Collectors.toMap(Entry::getKey, Entry::getValue,
                            (e1, e2) -> e1, LinkedHashMap::new));

推荐