初始化TreeMap
,TreeSet
等集合时,我们可以添加自定义比较器。
该代码看起来像:
Map<Integer, String> map1 = new TreeMap<>(new Comparator<Integer>() {
public int compare(Integer x, Integer y) {
return x-y;
}
});
现在,我们可以用lambda表达式替换此匿名实现。代码如下:
Map<Integer, String> map2 = new TreeMap<>((x,y) -> x-y);
Java-8允许您通过functional interfaces将lambda表达式存储在变量中。因此,我将上面的代码修改为以下代码:
BiFunction<Integer, Integer, Integer> myComparator = (x,y) -> x-y;
Map<Integer, String> map3 = new TreeMap<>(myComparator);
但是最后一次尝试没有成功!它给出了以下错误:
无法推断TreeMap的类型参数<>
为什么在上一个示例中无法解析类型?
注意:为了确认这不是IDE错误,我使用javac
执行了原始编译,但仍然给出相同的错误。
答案 0 :(得分:7)
尽管lambda表达式似乎相同,但是BiFunction
不是Comparator
,因此您不能互换它们。
Comparator<Integer> comparator = (x,y) -> x - y;
Map<Integer, String> map3 = new TreeMap<>(comparator);
让我们更深入地研究这些接口,并使用匿名类来实现它们:
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer x, Integer y) {
return x - y;
}
};
BiFunction<Integer, Integer, Integer> biFun = new BiFunction<Integer, Integer, Integer>() {
@Override
public Integer apply(final Integer x, final Integer y) {
return x - y;
}
};
区别也是方法的名称。 TreeMap
期望在其构造函数中使用Comparator
,因为其内部实现将根据与Comparator
的约定调用compare
。
顺便说一句,BinaryOperator<T>
也会产生相同的lambda表达式。
答案 1 :(得分:1)
这仅仅是因为TreeMap
构造函数期望Comparator<Integer>
而不是BiFunction
。
通过编写BiFunction<Integer, Integer, Integer> myComparator = ...
,您明确地告诉编译器该变量属于该类型。这样可以防止编译器将TreeMap
构造函数推断出所需的类型。由于BiFunction
不是Comparator
也不是它的子类,因此编译器不允许这样做。
答案 2 :(得分:0)
因为它期望比较器,并且您提供了BiFunction。 从Oracle文档:
AS
比较功能,对某些对象集合施加总排序。可以将比较器传递给排序方法(例如Collections.sort或Arrays.sort),以精确控制排序顺序。比较器还可以用于控制某些数据结构(例如排序集或排序映射)的顺序,或为没有自然顺序的对象集合提供排序。