Page 1 of 1

About Question enthuware.ocpjp.v8.2.1800 :

Posted: Fri Sep 22, 2017 8:32 am
by mrmartyn05
Slightly confused about method references, but struggling to put it into words, based on your explanation else where
Basically, when you do Supplier<MyProcessor> s = MyProcessor:new; you are telling the compiler to get you the constructor reference of the constructor that does not take any argument. This is because Supplier's functional method does not take any argument.
So MyProcess::new will meet fit the requirements for Supplier (Returning an object, and calling a method/constructor with no arguments because get() takes no arguments)

Code: Select all

public void debug(){         System.out.println(name+":"+marks);     }
...
slist.stream().forEach(Student::debug);
But in this question, how can you use a method reference for Consumer if the method has a no arguments and Consumer requires one argument for accept(T t).

Re: About Question enthuware.ocpjp.v8.2.1800 :

Posted: Fri Sep 22, 2017 9:17 pm
by admin
forEach expects a Consumer<Student> i.e. an object of a class that implements Consumer with a method accept(Student s);

Now, Student::debug is a reference to an instance method of Student. When you pass this method reference to forEach, an inner class will automatically be created like this:

Code: Select all

class SomeClass implements Consumer{
    public void accept(Student s){
       s.debug();
    }
}
Notice that here, everything except the call to s.debug() is boilerplate (i.e. common to all). Since each iteration of forEach already has a reference to a Student object, the compiler can easily deduce that it needs to invoke the debug() method on that instance. For this reason, compiler is OK with a method reference Student::debug.

The key to understand here is that there are no objects at compile time. You are only giving a hint to the compiler about the object that will there at run time and based on this hint, the compiler automatically creates the anonymous class that invokes method on appropriate object.

Re: About Question enthuware.ocpjp.v8.2.1800 :

Posted: Thu Sep 05, 2019 6:55 pm
by tylrdr
admin wrote:
Fri Sep 22, 2017 9:17 pm
forEach expects a Consumer<Student> i.e. an object of a class that implements Consumer with a method accept(Student s);

Now, Student::debug is a reference to an instance method of Student. When you pass this method reference to forEach, an inner class will automatically be created like this:

Code: Select all

class SomeClass implements Consumer{
    public void accept(Student s){
       s.debug();
    }
}
Notice that here, everything except the call to s.debug() is boilerplate (i.e. common to all). Since each iteration of forEach already has a reference to a Student object, the compiler can easily deduce that it needs to invoke the debug() method on that instance. For this reason, compiler is OK with a method reference Student::debug.

The key to understand here is that there are no objects at compile time. You are only giving a hint to the compiler about the object that will there at run time and based on this hint, the compiler automatically creates the anonymous class that invokes method on appropriate object.
Thank you for the explanation. Is it possible to write the same code with this SomeClass you wrote as anonymous class? I tried but failed. I would like to exchange slist.stream().forEach(Student::debug)
to a longer implementation without method reference.

I know I can do this:
studentList.stream().forEach(student -> student.debug());

But how to something like this with anonymous class(completely different example):

Code: Select all

interface FunctionalInterface2{

    int operation(int a, int b);
}

public class Calculator3 {

    int operate(int a, int b, FunctionalInterface2 functionalInterface2){
        return functionalInterface2.operation(a,b);
    }

    public static void main(String[] args) {
        Calculator3 calculator3 = new Calculator3();
        System.out.println(calculator3.operate(1,2,(a,b)->a+b));

        System.out.println(calculator3.operate(1, 4, new FunctionalInterface2() {
            @Override
            public int operation(int a, int b) {
                return a+b;
            }
        }));
    }
}

Re: About Question enthuware.ocpjp.v8.2.1800 :

Posted: Fri Sep 06, 2019 7:55 am
by admin
Yes, you could do :
new Consume()r{
public void accept(Student s){
s.debug();
}
}

Re: About Question enthuware.ocpjp.v8.2.1800 :

Posted: Sun Nov 03, 2019 7:31 pm
by tylrdr
I have a question:

I am confused why Student::debug is considered a Consumer.

If I change "public void debug()" to "public String debug()" it still accepts it as a Consumer.
But if I change "public void debug()" to "public void debug(double qq)" then it doesn't anymore.

Could someone please explain why that is?

Re: About Question enthuware.ocpjp.v8.2.1800 :

Posted: Tue Nov 05, 2019 12:12 pm
by admin
Student::debug is not considered Consumer. The information present in Student::debug is used by the compiler to create and instantiate a class that implements consumer that looks something like this:

Code: Select all

class CompilerGeneratedConsumer implements Consumer{
   public void consume(Student s){
     s.debug();
   }
} 
If you change Student's debug method to public void debug(double qq), how will you create a Consumer from it? Specifically, how will this call work? : s.debug( ***what will you pass as an argument here?***)

Changing the debug method to public String debug() is ok because you can still call s.debug(); and ignore the return value.

Re: About Question enthuware.ocpjp.v8.2.1800 :

Posted: Thu Nov 07, 2019 2:32 pm
by tylrdr
To anyone looking at this thread, user admin's excellent explanations and this example clarified it perfectly for me:

This is what Java does in the background, you can replace
studentList.stream().forEach(Student::debug);

with this, these are exactly the same:
studentList.stream().forEach( new Consumer<Student>() {
@Override
public void accept(Student student) {
student.debug();
}
});

Also it was important to understand that there are 4 (very) different method references:
1) Static methods
2) Instance methods on a particular instance
3) On an instance determined at runtime
4) Constructors

Student::debug is the 3rd in this list.

Read more at page 154 in OCP book.