Search code examples
javalambdajava-8comparatorfunctional-interface

Implementing a functional interface via method reference


First I got a class named after my Chinese name

public class Yxj<T> {
    private T[] data;
    private int size = 0;
    private final Comparator<? super T> comparator;
    public Yxj(Comparator<? super T> c) {
        data= (T[]) new Object[16];
        comparator = c;
    }

    public void addItem(T t){
        data[size++] = t;
    }

    public int sort(){
        return comparator.compare(data[0], data[1]);
    }


    public  T[] getData(){
        return data;
    }
}

in which a Comparator resides,then I defined a Norwich keeping a field order and setter and getter of it, finally there's a method used to implement the compare(T t1,T t2) in Comparator.

public class Norwich {
    private int order;


    public Norwich(int o) {
        order = o;
    }

    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        this.order = order;
    }


    public int compareOrder(Norwich n) {
        if (order > n.getOrder()) {
            return 2;
        } else if (order == n.getOrder()) {
            return 0;
        } else {
            return -3;
        }
    }
}

then here comes the main method

Yxj<Norwich> norwichYxj = new Yxj<>(Norwich::compareOrder);
norwichYxj.addItem(new Norwich(9));
norwichYxj.addItem(new Norwich(1));
System.out.println(norwichYxj.sort());

so what I'm interested in is that, why does not the method compareOrder keep the same parameters as the compare in Comparator but it can still work correctly?


Solution

  • It is simple. You have passed through the constructor your implementation of the Comparator to be used for comparing.

    Yxj<Norwich> norwichYxj = new Yxj<>(Norwich::compareOrder);
    

    Remember Comparator is nothing else than an interface. Since it is a functional interface, it can be represented through a lambda expression or a method reference (as you did). The way you can pass the Comparator in the full form is as follows. Note the usage of the compareOrder method:

    Yxj<Norwich> norwichYxj = new Yxj<>(new Comparator<>() {
        @Override
        public int compare(Norwich o1, Norwich o2) {
            return o1.compareOrder(o2);                      // usage of compareOrder
        }
    });
    

    This can be shortened to a lambda expression:

    Yxj<Norwich> norwichYxj = new Yxj<>((o1, o2) -> o1.compareOrder(o2));
    

    It can be shortened again to a method reference:

    Yxj<Norwich> norwichYxj = new Yxj<>(Norwich::compareOrder);
    

    Now you can see it can be represented in this way though the method compareOrder accepts only one formal parameter. The first parameter of the Comparator#compare method is the one invoking the compareOrder method and the second parameter is the one being passed to the compareOrder method.

    Learn more here: https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html


    Additionally, the classes you have constructed look a bit odd. Though the other answer doesn't in fact answer your question, it can lead you to a better code: Implementing a functional interface via method reference