Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why Java Method Reference of instance method cannot be assigned to Consumer interface

Tags:

java

lambda

Here is my Code :

public class SearchByLambda {

     private Map<String,Consumer<Person>> searchCritertiaHolder = new HashMap<String,Consumer<Person>>();

     private static final String AGED = "aged";

     public SearchByLambda(){
           searchCritertiaHolder.put(AGED, (Person p)-> {p.filterAgedPerson(p);} );
     }

     private Consumer<Person> getFilter(String personType){
          return searchCritertiaHolder.get(personType);
     }

     public static void main(String[] args) {
          SearchByLambda searchUsage = new SearchByLambda();
          Person p = new Person(59,"shailesh");
          Person p1 = new Person(58,"ganesh");

          searchUsage.getFilter(AGED).accept(p);
          searchUsage.getFilter(AGED).accept(p1);

          Person.printAgedPersons();
     }
 }

 class Person{

       private static List<Person> agedPersons = new ArrayList<>();

       private int age;

       private String name;

       public int getAge() {
              return age;
       }

       public void setAge(int age) {
          this.age = age;
       }

       public String getName() {
            return name;
       }

       public void setName(String name) {
            this.name = name;
       }

       public Person(int age,String name){
           this.age = age;
           this.name = name;
       }

       public void filterAgedPerson(Person person){
          if(person.getAge() > 58){
              agedPersons.add(person);
          }
       }

       public static void printAgedPersons(){
            for(Person person : agedPersons){
                System.out.println(person.getName());
            }
       }
 }

When I replace following Lambda expression

     searchCritertiaHolder.put(AGED, (Person p)-> {p.filterAgedPerson(p);});

with

              searchCritertiaHolder.put(AGED, Person::filterAgedPerson);

it gives me compilation error. I am using java 8 and and compiling through eclipse. Why is this so? Why cannot I assign method reference for instance method of any arbitrary object to consumer functional interface?

like image 411
Shailesh Vaishampayan Avatar asked Oct 18 '15 22:10

Shailesh Vaishampayan


People also ask

What is consumer interface in Java?

Java Consumer Interface It is a functional interface defined in java.util.function package. It contains an abstract accept () and a default andThen () method. It can be used as the assignment target for a lambda expression or method reference.

What are method references in Java?

Method references are simple, easy-to-read lambda expressions to call/refer and existing method by name in a lambda expression. Following is the syntax to reference a instance method in Java

What is an example of a reference to an instance method?

The following is an example of a reference to an instance method of a particular object: The method reference myComparisonProvider::compareByName invokes the method compareByName that is part of the object myComparisonProvider. The JRE infers the method type arguments, which in this case are (Person, Person).

What is the difference between instance methods and methods in Java?

A method is a function written inside the class. Since java is an object-oriented programming language, we need to write a method inside some classes. Instance methods can access instance variables and instance methods directly and undeviatingly. Instance methods can access static variables and static methods directly.


1 Answers

Your definition of filterAgedPerson takes a Person as an argument, even though it is not a static method. It doesn't need to, and it shouldn't if you want to use it as a Consumer<Person>. What you are ending up with is something compatible with BiConsumer<Person, Person>.

It might help to think of it this way: method references to non-static methods always take an "extra" argument which is used as this.

The easiest way for you to fix this with your current code structure is to modify the filterAgedPerson method to not take a Person as an argument

   public void filterAgedPerson() {
      if (this.getAge() > 58) {
          agedPersons.add(person);
      }
   }

As an aside, you might want to also consider making your filters Predicate<Person> instead of Consumer<Person> and moving the results handling elsewhere. This will give you more flexibility as things get more complicated.

like image 176
clstrfsck Avatar answered Sep 21 '22 18:09

clstrfsck