为什么不能取消引用 lambda 表达式?
Why lambda expression cannot be dereferenced?
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) -> 0
和 c2 = (str1, str2) -> 1
,
那为什么
c1.thenComparing(c2)
工作正常并且
((str1, str2) -> 0).thenComparing((str1, str2) -> 1)
是不是?
Java 依赖于 lambda 表达式的上下文来确定其类型。将 lambda 分配给变量或将其作为方法参数传递可提供足够的上下文,但在 lambda 上调用方法(例如 thenComparing()
)根本不会提供任何有用的上下文。
这应该有效:
Comparator <String> c1 = (str1, str2) -> 0;
TreeMap <String, Double> tm2 = new TreeMap(c1.thenComparing((str1, str2) -> 1));
更详细:
lambda 表达式的计算结果为实现某些功能接口的类型的对象,并且 Java 依赖于表达式出现的上下文来确定 哪个 功能即界面。在第二种情况下,构造函数参数不是 lambda 的上下文; thenComparing()
的调用是。该方法的 return 值是构造函数参数。但是在 Java 可以确定关于 thenComparing()
的 anything 之前,它需要知道调用它的对象的类型。类型通知方法,而不是相反。
Java 不能从参数类型向后工作到所需的 lambda 类型,因为可能有任意数量的功能接口都可以工作。 Java 不能假设所需的接口在标准库中。
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
是 Foo
还是 Comparator<String>
。推理不会以这种方式向后工作。
这是 Java 中类型推断的限制。
首先,您使用原始类型,比较器将解析为 Comparator
而不是 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
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) -> 0
和 c2 = (str1, str2) -> 1
,
那为什么
c1.thenComparing(c2)
工作正常并且
((str1, str2) -> 0).thenComparing((str1, str2) -> 1)
是不是?
Java 依赖于 lambda 表达式的上下文来确定其类型。将 lambda 分配给变量或将其作为方法参数传递可提供足够的上下文,但在 lambda 上调用方法(例如 thenComparing()
)根本不会提供任何有用的上下文。
这应该有效:
Comparator <String> c1 = (str1, str2) -> 0;
TreeMap <String, Double> tm2 = new TreeMap(c1.thenComparing((str1, str2) -> 1));
更详细:
lambda 表达式的计算结果为实现某些功能接口的类型的对象,并且 Java 依赖于表达式出现的上下文来确定 哪个 功能即界面。在第二种情况下,构造函数参数不是 lambda 的上下文; thenComparing()
的调用是。该方法的 return 值是构造函数参数。但是在 Java 可以确定关于 thenComparing()
的 anything 之前,它需要知道调用它的对象的类型。类型通知方法,而不是相反。
Java 不能从参数类型向后工作到所需的 lambda 类型,因为可能有任意数量的功能接口都可以工作。 Java 不能假设所需的接口在标准库中。
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
是 Foo
还是 Comparator<String>
。推理不会以这种方式向后工作。
这是 Java 中类型推断的限制。
首先,您使用原始类型,比较器将解析为 Comparator
而不是 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