1
import java.util.*;

class TreeMapDemo
{
    public static void main(String args[])
    {
        Comparator <String> c1 = (str1, str2) -> 0;

        Comparator <String> c2 = (str1, str2) -> 1;

        TreeMap <String, Double> tm1 = new TreeMap(c1.thenComparing(c2));
        //Working fine

        TreeMap <String, Double> tm2 = new TreeMap(((str1, str2) -> 0).thenComparing((str1, str2) -> 1));
        //Error: Lambda expression not expected here
        //<none> can not be dereferenced
    }
}

我的查询是:

如果

c1 = (str1, str2) -> 0c2 = (str1, str2) -> 1,

那么为什么

c1.thenComparing(c2)工作正常并且

((str1, str2) -> 0).thenComparing((str1, str2) -> 1)不是?

4

3 回答 3

7

Java 依赖于 lambda 表达式的上下文来确定其类型。将 lambda 分配给变量或将其作为方法参数传递可以提供足够的上下文,但是thenComparing()在 lambda 上调用方法(例如)根本没有提供有用的上下文。

这应该有效:

Comparator <String> c1 = (str1, str2) -> 0;
TreeMap <String, Double> tm2 = new TreeMap(c1.thenComparing((str1, str2) -> 1));

更详细地说:

一个 lambda 表达式的计算结果是一个实现了某个功能接口的类型的对象,Java 依赖于表达式出现的上下文来确定是哪个功能接口。在第二种情况下,构造函数参数不是 lambda 的上下文;的调用thenComparing()是。该方法的返回值是构造函数参数。但是在 Java 可以确定任何关于thenComparing()它的东西之前,需要知道调用它的对象的类型。类型通知方法,而不是相反。

Java 不能从参数类型向后工作到所需的 lambda 类型,因为可能有任意数量的函数式接口可以工作。Java 不能假定想要的接口在标准库中。

于 2015-09-13T23:09:53.510 回答
4

Lambda 表达式必须针对特定类型。

c1 = (str1, str2) -> 0;

没关系,因为类型c1是已知的。

就其本身(str1, str2) -> 0而言是模棱两可的。

例如

BiFunction<String, String, Integer> x = (str1, str2) -> 0;

也有道理。

为了具体说明,请看这个例子。

public interface Foo extends BiFunction<String, String, Integer> {
    default Comparator<String> thenComparing(Comparator<String> comparator) {
        return String.CASE_INSENSITIVE_ORDER;
    }
}

public static void main(String[] args) {
    Foo foo = (str1, str2) -> 0;        // overriding the sole method of BiFunction
    TreeMap<String, Double> treeMap = new TreeMap<>(foo.thenComparing((str1, str2) -> 1));
}

这编译得很好。所以如果我们只写

new TreeMap<>((str1, str2) -> 0).thenComparing((str1, str2) -> 1));

编译器无法知道(str1, str2) -> 0是 aFoo还是 a Comparator<String>。推理不能以这种方式向后工作。

于 2015-09-13T23:13:52.560 回答
0

那是Java中类型推断的限制。首先,您使用原始类型,比较器将被解析为 aComparator而不是Comparator<String>

TreeMap <String, Double> tm1 = new TreeMap((str1, str2) -> 0);// wouldn't work

在哪里

TreeMap <String, Double> tm1 = new TreeMap<>((str1, str2) -> 0);// works

现在,您不能在推断之前调用类型的特定方法。

Comparator<String> c1 = ((str1, str2) -> 0).thenComparing((str1, str2) -> 1); // doesn't work

除非你为编译器提供一些额外的帮助

Comparator <String> c1 = ((Comparator<String>)((str1, str2) -> 0)).thenComparing((str1, str2) -> 1); // works
于 2015-09-13T23:46:02.953 回答