Page 1 of 1

About Question enthuware.ocpjp.v8.2.1857 :

Posted: Wed Apr 24, 2019 1:00 am
by rois_r

Code: Select all

class MyProcessor {
	Integer value;

	public MyProcessor(Integer value) {
		this.value = value;
	}

	public void process() {
		System.out.println(value + " ");
	}
}

public class TestClass {
	public static void main(String[] args) {         
		List<Integer> ls = Arrays.asList(1, 2, 3);                  
		//INSERT CODE HERE     
		}
	}
}
Solution: ls.stream().map(MyProcessor::new).forEach(MyProcessor::process);

Why this works if forEach needs a Consumer and process method does not take any argument?

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

Posted: Wed Apr 24, 2019 1:11 am
by admin
The argument is not passed to the process method. First, the map method converts each element of List<Integer> to List<MyProcessor> because of map(MyProcessor::new). Next, a Consumer object is created using the method reference MyProcessor::process, something like this:

Code: Select all

new Consumer(){
   void accept(MyProcessor mp){
     mp.process(); <---- No argument required here
   }
}
This consumer object is passed to forEach.

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

Posted: Thu Apr 25, 2019 2:05 pm
by rois_r
Thanks for the explanation!

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

Posted: Mon Jul 27, 2020 10:31 am
by Javier
Hi Paul!
Why the last two options are syntactically illegal?
What I see is that in both cases the method references doesn´t work on the body of the lambda expression.

Code: Select all

ls.stream().forEach((x)->process( MyProcessor::new ));//not compile

Code: Select all

ls.stream().forEach(x->{new MyProcessor(x).process();}); //compile

Code: Select all

ls.stream().forEach(x->MyProcessor::new);//not compile

Code: Select all

ls.stream().forEach(MyProcessor::new);//compile
Both options work when we don´t use method references.
I wrote this code in Eclipse and I don´t understand why the errors.

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

Posted: Mon Jul 27, 2020 10:47 am
by admin
Check out how lambda expressions are converted by the compiler into a class. How do you think they will be converted to a class with a method by the compiler?

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

Posted: Mon Jul 27, 2020 1:35 pm
by Javier
Hi Paul,
I don´t get it, I am not able to find the correct answer, but I saw one possible answer here:
https://stackoverflow.com/questions/168 ... e-compiled
"Java compiler will generate synthetic methods"
"Instead of creating a new object that will wrap the Lambda function, it uses the new INVOKEDYNAMIC instruction to dynamically link this call site to the actual Lambda function which is converted to private static synthetic lambda$0(Ljava/lang/String;)V which will accept string as a parameter."
I am very lost here, I don´t get it. :(

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

Posted: Tue Jul 28, 2020 12:34 am
by admin
What I meant was that lambda expressions are just syntactic sugar. The JVM doesn't understand lambda expressions. Conceptually, the compiler simply converts the given lambda expression into some class, instantiates it, and passes that object to the method. While doing so, it follows certain process and rules. It puts the part after -> as the method body.

Let's see this now:
1. ls.stream().forEach((x)->process( MyProcessor::new ));

forEach expects an object of a class that implements Consumer. So, the compiler uses the code given in the lambda expression and creates this class and an object of that class. For example, in this case, it will do:

Code: Select all

class SomeMadeUpClassName implements Consumer{
   public void accept(Integer x){
        process(new MyProcessor()); //this is illegal because you cannot invoke MyProcessor's process method like this.

   }
}
What you really want in the body of the above accept method is this line of code: new MyProcessor(x).process();

Please note that this is a long topic to discuss in a post but I have tried to explain it in brief. You need go through a good book to understand how lambdas and method references work.

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

Posted: Thu Mar 21, 2024 8:59 am
by likejudo
I liked the explanation in the solution. The explanation of method references. It was better than the textbook!

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

Posted: Mon Apr 01, 2024 11:07 pm
by cupdescent
admin wrote:
Tue Jul 28, 2020 12:34 am
What I meant was that lambda expressions are just syntactic sugar. The JVM doesn't understand lambda expressions. Conceptually, the compiler simply converts the given lambda expression into some class, instantiates it, and passes that object to the method. While doing so, it follows certain process and rules. It puts the part after -> as the method body.

Let's see this now:
1. ls.stream().forEach((x)->process( MyProcessor::new ));

forEach expects an object of a class that implements Consumer. So, the compiler uses the code given in the lambda expression and creates this class and an object of that class. For example, in this case, it will do:

Code: Select all

class SomeMadeUpClassName implements Consumer{
   public void accept(Integer x){
        process(new MyProcessor()); //this is illegal because you cannot invoke MyProcessor's process method like this.

   }
}
What you really want in the body of the above accept method is this line of code: new MyProcessor(x).process();

Please note that this is a long topic to discuss in a post but I have tried to explain it in brief. You need go through a good book to understand how lambdas and method references work.
Good to know. :)