About Question enthuware.ocpjp.v8.2.1858 :

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

Moderator: admin

Post Reply
aphonso@gmail.com
Posts: 2
Joined: Sun Sep 02, 2018 7:25 am
Contact:

About Question enthuware.ocpjp.v8.2.1858 :

Post by aphonso@gmail.com »

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

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

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

Post by admin »

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:

Code: Select all

class CompilerCreatedConsumer implements Consumer{
  public void accept(String genre){
       genreList.add(genre); //focus on this line 
  }
}
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.
If you like our products and services, please help us by posting your review here.

aphonso@gmail.com
Posts: 2
Joined: Sun Sep 02, 2018 7:25 am
Contact:

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

Post by aphonso@gmail.com »

Perfect explanation, thank you so much!

bkazooie
Posts: 4
Joined: Thu Jun 27, 2019 6:12 am
Contact:

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

Post by bkazooie »

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

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

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

Post by admin »

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

bkazooie
Posts: 4
Joined: Thu Jun 27, 2019 6:12 am
Contact:

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

Post by bkazooie »

thank you Paul

Seán Kennedy
Posts: 12
Joined: Wed Feb 17, 2021 6:55 am
Contact:

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

Post by Seán Kennedy »

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.

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
class files generated
Q1858 b.PNG (6.38 KiB) Viewed 1497 times
javap output
javap output
Q1858.PNG (24.33 KiB) Viewed 1497 times

Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 38 guests