使用BiFunction代替比较器不起作用

时间:2019-04-12 14:21:21

标签: java lambda java-8 comparator functional-interface

初始化TreeMapTreeSet等集合时,我们可以添加自定义比较器。 该代码看起来像:

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执行了原始编译,但仍然给出相同的错误。

3 个答案:

答案 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),以精确控制排序顺序。比较器还可以用于控制某些数据结构(例如排序集或排序映射)的顺序,或为没有自然顺序的对象集合提供排序。