About Question enthuware.ocpjp.v8.2.1800 :

Help and support on OCA OCP Java Programmer Certification Questions
1Z0-808, 1Z0-809, 1Z0-815, 1Z0-816, 1Z0-817

Moderator: admin

Post Reply
mrmartyn05
Posts: 1
Joined: Fri Sep 22, 2017 8:18 am
Contact:

About Question enthuware.ocpjp.v8.2.1800 :

Post 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).

admin
Site Admin
Posts: 10046
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

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

Post 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.
If you like our products and services, please help us by posting your review here.

tylrdr
Posts: 6
Joined: Sun Sep 01, 2019 9:33 am
Contact:

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

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

admin
Site Admin
Posts: 10046
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

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

Post by admin »

Yes, you could do :
new Consume()r{
public void accept(Student s){
s.debug();
}
}
If you like our products and services, please help us by posting your review here.

tylrdr
Posts: 6
Joined: Sun Sep 01, 2019 9:33 am
Contact:

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

Post 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?

admin
Site Admin
Posts: 10046
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

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

Post 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.
If you like our products and services, please help us by posting your review here.

tylrdr
Posts: 6
Joined: Sun Sep 01, 2019 9:33 am
Contact:

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

Post 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.

Post Reply

Who is online

Users browsing this forum: No registered users and 74 guests