Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using BiFunction in place of a Comparator does not work

While initializing collections like TreeMap, TreeSet, etc. We can add our custom comparator. The code looks something like:

Map<Integer, String> map1 = new TreeMap<>(new Comparator<Integer>() {
    public int compare(Integer x, Integer y) {
        return x-y;
    }
});

Now, we can make replace this anonymous implementation with a lambda expression. The code would look like:

Map<Integer, String> map2 = new TreeMap<>((x,y) -> x-y);

Java-8 allows you to store lambda expressions in a variable through functional interfaces. So, I modified the above code to the following:

BiFunction<Integer, Integer, Integer> myComparator = (x,y) -> x-y;
Map<Integer, String> map3 = new TreeMap<>(myComparator);

But this last attempt did not work! It gave the following error:

Cannot infer type arguments for TreeMap<>

Why did it fail to resolve types in the last example?

Note: To confirm that this is not an IDE bug, I performed a raw compile using javac and it still gave the same error.

like image 867
YetAnotherBot Avatar asked Jan 01 '23 01:01

YetAnotherBot


2 Answers

Although the lambda expression seems the same, the BiFunction is not the Comparator therefore you cannot interchange them.

Comparator<Integer> comparator = (x,y) -> x - y;
Map<Integer, String> map3 = new TreeMap<>(comparator);

Let's take a look deeper into these interfaces and implement them using an anonymous class:

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;
    }
};

The difference is also the name of the method. TreeMap expects Comparator in its constructor because its internal implementation will call compare according to the contract with Comparator.

By the way, the BinaryOperator<T> results in the same lambda expression as well.

like image 52
Nikolas Charalambidis Avatar answered Jan 08 '23 02:01

Nikolas Charalambidis


That is simply because the TreeMap constructor expects a Comparator<Integer> rather than a BiFunction.

With writing BiFunction<Integer, Integer, Integer> myComparator = ... you explicitly say to the compiler that the variable is of that type. This prevents the compiler from infering the type required to the TreeMap constructor. Since BiFunction is not a Comparator, nor a subclass of it, the compiler does not allow this.

like image 20
MC Emperor Avatar answered Jan 08 '23 01:01

MC Emperor