About Question enthuware.ocpjp.v8.2.1858 :
Moderator: admin
-
- Posts: 2
- Joined: Sun Sep 02, 2018 7:25 am
- Contact:
About Question enthuware.ocpjp.v8.2.1858 :
Can anyone please help me understanding the following code? It compiles but I don't understand why!
My question is, how come the Stream "void forEach(Consumer<? super T> action)" can work with the List method "Boolean add(E e)"? The way I see it, the List, add method is a Function<E, Boolean> and not a Consumer<E>.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Book {
private String title;
private String genre;
public Book(String title, String genre) {
this.title = title;
this.genre = genre;
}
//accessors not shown
}
public class DoubtStreamsForEach {
public static void main(String[] args) {
List<Book> books = Arrays.asList(new Book("Gone with the wind", "Fiction"),
new Book("Bourne Ultimatum", "Thriller"), new Book("The Client", "Thriller"));
List<String> genreList = new ArrayList<>();
books.stream().map(Book::getGenre).forEach(genreList::add); //how can a consumer return a boolean?
}
}
My question is, how come the Stream "void forEach(Consumer<? super T> action)" can work with the List method "Boolean add(E e)"? The way I see it, the List, add method is a Function<E, Boolean> and not a Consumer<E>.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Book {
private String title;
private String genre;
public Book(String title, String genre) {
this.title = title;
this.genre = genre;
}
//accessors not shown
}
public class DoubtStreamsForEach {
public static void main(String[] args) {
List<Book> books = Arrays.asList(new Book("Gone with the wind", "Fiction"),
new Book("Bourne Ultimatum", "Thriller"), new Book("The Client", "Thriller"));
List<String> genreList = new ArrayList<>();
books.stream().map(Book::getGenre).forEach(genreList::add); //how can a consumer return a boolean?
}
}
-
- Site Admin
- Posts: 10053
- Joined: Fri Sep 10, 2010 9:26 pm
- Contact:
Re: About Question enthuware.ocpjp.v8.2.1858 :
I am not sure what you mean by "add method is a function".
The call to forEach expects a Consumer and when you do forEach(genreList::Add), you are telling the compiler to create a Consumer using a method reference that points to genreList.add. So the compiler creates an anonymous class that implements the consumer interface and it implements the accept to use genreList.add. Something like this:
As you can see above, List's add method is used inside the accept method of the Consumer.
You can visualize the call to .forEach(genreList::add); like this:
.forEach( new CompilerCreatedConsumer() );
Of course, the above is not the exact code generated by the compiler but it illustrates what the compiler does in principle. You can, in fact, decompile the generated code and verify.
HTH,
Paul.
The call to forEach expects a Consumer and when you do forEach(genreList::Add), you are telling the compiler to create a Consumer using a method reference that points to genreList.add. So the compiler creates an anonymous class that implements the consumer interface and it implements the accept to use genreList.add. Something like this:
Code: Select all
class CompilerCreatedConsumer implements Consumer{
public void accept(String genre){
genreList.add(genre); //focus on this line
}
}
You can visualize the call to .forEach(genreList::add); like this:
.forEach( new CompilerCreatedConsumer() );
Of course, the above is not the exact code generated by the compiler but it illustrates what the compiler does in principle. You can, in fact, decompile the generated code and verify.
HTH,
Paul.
If you like our products and services, please help us by posting your review here.
-
- Posts: 2
- Joined: Sun Sep 02, 2018 7:25 am
- Contact:
Re: About Question enthuware.ocpjp.v8.2.1858 :
Perfect explanation, thank you so much!
-
- Posts: 4
- Joined: Thu Jun 27, 2019 6:12 am
- Contact:
Re: About Question enthuware.ocpjp.v8.2.1858 :
Hi admin
Sorry for english, but I can't understand this statement
genreList = books.stream().map(Book::getGenre).collect(Collectors.toList());
Why Book::getGenre will compile? we have to guess that getGenre is static? I am a little bit confused because in this other line:
books.stream().map(b->b.getGenre()).forEach(genreList::add)
we pass the add method through the object genreList which is an instantiated object
Sorry for english, but I can't understand this statement
genreList = books.stream().map(Book::getGenre).collect(Collectors.toList());
Why Book::getGenre will compile? we have to guess that getGenre is static? I am a little bit confused because in this other line:
books.stream().map(b->b.getGenre()).forEach(genreList::add)
we pass the add method through the object genreList which is an instantiated object
-
- Site Admin
- Posts: 10053
- Joined: Fri Sep 10, 2010 9:26 pm
- Contact:
Re: About Question enthuware.ocpjp.v8.2.1858 :
Book::getGenre is just a method reference, which means you are telling that you want to use the method named getGenre in Book class. It does not mean that this method is static or instance. The compiler looks into the Book class to find out whether it is static or instance. It generates different code depending on whether it is static or not.
If the method is instance method, then the compiler uses the reference to the object that is available in the context, if the method is static, it will use the Class name.
If the method is instance method, then the compiler uses the reference to the object that is available in the context, if the method is static, it will use the Class name.
If you like our products and services, please help us by posting your review here.
-
- Posts: 4
- Joined: Thu Jun 27, 2019 6:12 am
- Contact:
Re: About Question enthuware.ocpjp.v8.2.1858 :
thank you Paul
-
- Posts: 12
- Joined: Wed Feb 17, 2021 6:55 am
- Contact:
Re: About Question enthuware.ocpjp.v8.2.1858 :
Hi Paul,
Firstly, I think you explanation is excellent. I am trying to use javap to re-inforce your explanation - especially e.g. how the return type of "add" was ignored. However, I am finding the javap output impossible to decipher - there is nothing like your clear code in it (see attached screenshot). Also, Netbeans is not generating any extra class files (no anonymous inner classes on the hard disk)? I was expecting one for Consumer and another for Function (see attached screenshot). Not sure what is going on...
If there was a nice tool to "present" the code as you explained it i.e. the implementation class that implements Consumer, that would be great - is there one?
Thanks,
Seán.
Firstly, I think you explanation is excellent. I am trying to use javap to re-inforce your explanation - especially e.g. how the return type of "add" was ignored. However, I am finding the javap output impossible to decipher - there is nothing like your clear code in it (see attached screenshot). Also, Netbeans is not generating any extra class files (no anonymous inner classes on the hard disk)? I was expecting one for Consumer and another for Function (see attached screenshot). Not sure what is going on...
If there was a nice tool to "present" the code as you explained it i.e. the implementation class that implements Consumer, that would be great - is there one?
Thanks,
Seán.
Code: Select all
package ocp.java_stream_api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Q2_1858 {
public static void main(String[] args) {
List<AnotherBook> books = Arrays.asList(
new AnotherBook("Gone with the wind", "Fiction"),
new AnotherBook("Bourne Ultimatum", "Thriller"),
new AnotherBook("The Client", "Thriller") );
List<String> genreList = new ArrayList<>();
books.stream()
.map(AnotherBook::getGenre)
.forEach(s->genreList.add(s));
System.out.println(genreList);
}
}
- Attachments
-
- class files generated
- Q1858 b.PNG (6.38 KiB) Viewed 1497 times
-
- javap output
- Q1858.PNG (24.33 KiB) Viewed 1497 times
Who is online
Users browsing this forum: Bing [Bot] and 38 guests