Beast
Beast

Reputation: 629

Why does the method reference I am passing to Arrays.sort need to be static?

I am new bie to Java 8. I am trying to create a sample for Reference to an instance method of an arbitrary object of a particular type.

I have a person class with one field Name and trying to sort Array of Person objects on firstName field of person class.

public class Person{

    String firstName;

    public Person(String firstName) {
        super();
        this.firstName = firstName;
    }

    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public int compareByFirstName(Person p1, Person p2) {
        return p1.getFirstName().compareTo(p2.getFirstName());
    }

}

public class TestInstanceMethorRefArbObjSample {

    public static void main(String[] args) {
        TestInstanceMethorRefArbObjSample obj=new TestInstanceMethorRefArbObjSample();
        obj.personSorting();
    }

    private void personSorting() {
        Person[] personArr= {new Person("Jinesh"),new Person("Sejal"),new Person("Ashish")};
        Arrays.sort(personArr,Person::compareByFirstName);
    }
}

But I am facing compilation issue on below line.

Arrays.sort(personArr,Person::compareByFirstName);

1.The type Person does not define compareByFirstName(T, T) that is applicable here TestInstanceMethorRefArbObjSample.java /InstaceMethodArbitaryObjectProject/src/com/methodreference/instancemethodrefarbitary/client line 11 Java Problem 2.The type Person does not define compareByFirstName(T, T) that is applicable here TestInstanceMethorRefArbObjSample.java /InstaceMethodArbitaryObjectProject/src/com/methodreference/instancemethodrefarbitary/client line 11 Java Problem

I am just trying to pass the implementation of int compare(T o1, T o2); using compareByFirstname of Person class.

As soon as I am changing the method compareByFirstname of Person class to static everything is working fine.

Why I need to change the compareByFirstname to static method to make it work?

Upvotes: 1

Views: 711

Answers (2)

Max Vollmer
Max Vollmer

Reputation: 8598

Some background

Arrays.sort expects a Comparator, which, when passing a method reference, must be a method that accepts two instances of the appropriate type.

There are two ways to create such a method:

  1. Create a static method in any class that accepts two parameters of the appropriate type. This is essentially what you have done. Such a method does not need to be declared in the specific class, you could also have some other class that provides such helper methods.

Your compiler will make sure that the generated Comparator instance calls the referenced method with the 2 instances it wants to compare.

  1. Create an instance method in the specific class for that type that accepts one parameter of the appropriate type.

Your compiler will make sure that the generated Comparator instance calls the referenced method on the 1st instance with the 2nd instance as parameter.

Your specific case

Since your method takes two parameters, it must be static, as it otherwise needs a third instance to run. Either declare it static, or remove one parameter and implement the comparison between this and the parameter.

Upvotes: 3

drmathias
drmathias

Reputation: 39

You are using a method reference and since you have written it as Person::compareByFirstName it is referencing a static method. If you wanted to reference an instance method instead you would need to first create an instance of the object, then you would reference the method with the instance, like so:

Person p = new Person("");
p::compareByFirstName

However this would not be what you want to do in your case as the compare method is not instance-specific.

You could change your comparison method to make it specific to the instance by comparing the object instance with another object

public int compareByFirstName(Person p2) {
    return this.getFirstName().compareTo(p2.getFirstName());
}

In which case you would be able to use the method reference Person::compareByFirstName as the comparison becomes arbitary.

Upvotes: 1

Related Questions