About Question enthuware.ocpjp.v8.2.1789 :

Moderator: admin

Post Reply
mrmuiz
Posts: 49
Joined: Mon Jul 27, 2015 4:34 am
Contact:

About Question enthuware.ocpjp.v8.2.1789 :

Post by mrmuiz » Sat Oct 17, 2015 11:36 am

But the argument for forEach method requires a method that takes an argument. The forEach method basically invokes the passed method and gives that method an element of the list as an argument.
I think that, put in this way, it's a bit misleading. I'd say that
the argument for forEach method of a Collection<T> object requires
  1. a method that takes an argument of type T, or
  2. a method of the class T
Referring to the question, these are two examples, one for each case
  1. Code: Select all

    n.getList().forEach(System.out::print);
  2. Code: Select all

    n.getList().forEach(String::toString); //note that String::toString doesn't take any argument

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

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

Post by admin » Sat Oct 17, 2015 9:49 pm

That may not be true. Because in case of Collection<String>, T is String while System.out::print takes Object.
What you are saying describes what the argument for forEach should be. What the explanation is saying is what actually happens to the objects in the collection wrt to the method reference that is passed in as the argument in forEach.
HTH,
Paul.
If you like our products and services, please help us by posting your review here.

mrmuiz
Posts: 49
Joined: Mon Jul 27, 2015 4:34 am
Contact:

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

Post by mrmuiz » Mon Oct 19, 2015 2:51 am

Sure, my proposed answer is highly perfectible, I just wanted to give you a sense of what I meant.
The part I cited seems to refer to a general behaviour, for how it's written.
Maybe it's just me.

lenalena
Posts: 56
Joined: Tue Feb 21, 2017 4:24 pm
Contact:

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

Post by lenalena » Sat May 13, 2017 4:37 pm

The test code also doesn't compile because printNames is not static but is referenced from static void main (aka static context).

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

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

Post by admin » Sat May 13, 2017 8:24 pm

Did you try compiling it?
If you like our products and services, please help us by posting your review here.

lenalena
Posts: 56
Joined: Tue Feb 21, 2017 4:24 pm
Contact:

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

Post by lenalena » Mon May 15, 2017 2:11 pm

Yes. When compiled as is, the error given is:
error: incompatible types: invalid method reference
n.getList().forEach(Test::printNames);
^
method printNames in class Test cannot be applied to given types
required: no arguments
found: String
reason: actual and formal argument lists differ in length
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
However, when I add a String param to the method printNames, like this:

Code: Select all

   public void printNames(String name){
        System.out.println(getList());
    }
And try to compile, the compiler error is:
error: incompatible types: invalid method reference
n.getList().forEach(Test::printNames);
^
cannot find symbol
symbol: method printNames(String)
location: class Test
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error
Then, if I add static to the printNames:

Code: Select all

public static void printNames(String name){
        //System.out.println(getList());  
    }
It compiles fine, without any issues. (Note, commented out method body to prevent non-static call to getList()

Compiled using command prompt, no IDE. javac version 1.8.0_121

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

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

Post by admin » Mon May 15, 2017 11:48 pm

No, that is an incorrect interpretation. It is possible to reference a non-static method from a static method as long as you are invoking the non-static method on a valid object reference.
In this case, when the method reference Names::printNames will invoked the printNames method on each object returned by forEach.

It will not compile just by changing the printNames method to static. As you posted above, you had to comment out the call to System.out.println(getList()); as well.

HTH,
Paul.
If you like our products and services, please help us by posting your review here.

lenalena
Posts: 56
Joined: Tue Feb 21, 2017 4:24 pm
Contact:

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

Post by lenalena » Tue May 16, 2017 9:12 am

Paul, I'm sorry, I think I'm missing a big concept here, but I still don't get it. I think the fact that I commented out getList() call from printNames just proves my point, not disproves it.

So I left printNames(String s) completely empty. If I remove static keyword - it doesn't compile (with the error in second example above). If I add static keyword - it does. How can it be said, then, that compilation error is NOT due to non-static reference from a static context?

The compiler doesn't even see the method unless it is made static.

The necessity to comment out getList () was just a waterfall effect - when getNames became static - then it in turn started making a non-static reference to getList. I added System.out.println(getList()) back to static printNames and tried to recompile, and got the following error:
error: non-static method getList() cannot be referenced from a static context
System.out.println(getList());
^
1 error
Now there is a more direct message.

I agree with your general statement, that
It is possible to reference a non-static method from a static method as long as you are invoking the non-static method on a valid object reference.
After all, the static main method is successfully calling getLest() on the non-static TestClass reference it just created. However, I do not think that forEach does something similar, in this case anyway. If it had, then indeed non-static printNames could have been invoked on an element. And the presence or absence of any method body in printNames would have been irrelevant - after all, it would just be a method call. But the compiler is not allowing a non-static call to printNames, so method reference to a non-static method is not allowed in a static context, even though it will be applied to a valid non-static object reference returned by forEach.

I hope that wasn't too confusing. Thank you for reading and working through this with me!

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

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

Post by admin » Tue May 16, 2017 10:36 am

The original method was:
public void printNames(){
System.out.println(getList());
}
and you changed it to:
public static void printNames(String x){
}

In my view, you have changed everything about the method (including its signature as well as business logic) and not just made it static from non-static. Yes, it compiles but it the not the same method at all. If static/non-static were the real issue, you would not have had to make other changes.

The simple and most straight forward reason is what is given in the explanation, which is -
n.getList().forEach(Names::printNames); should be changed to simply: n.printNames();

It is not the method printNames that has a problem. It is the statement in which it is referenced that has a problem.

HTH,
Paul.
If you like our products and services, please help us by posting your review here.

lenalena
Posts: 56
Joined: Tue Feb 21, 2017 4:24 pm
Contact:

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

Post by lenalena » Tue May 16, 2017 11:54 am

My reason for not compiling is the secondary reason. Of course, the reason given in the solution - the fact that printNames() takes to arguments - is the primary reason. However, IF that were the only reason, then adding a String parameter to printNames would have fixed the problem. However, even when printNames gets a parameter so that the signature would fit the required consumer signature - then it STILL doesn't compile - because of the (secondary) static issue. (IMHO).

lucastomasini
Posts: 3
Joined: Tue Jun 20, 2017 3:10 pm
Contact:

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

Post by lucastomasini » Sat Jun 24, 2017 1:18 pm

If I add any argument to the printNames method, for example:

public void printNames(String hola){
System.out.println(getList());
}

It still doesn't compile because the compiler can't infer from the context what instance of printNames to use (printNames is not a static method). I got the error:

error: incompatible types: invalid method reference
n.getList().forEach(Names::printNames);
cannot find symbol
symbol: method printNames(String)
location: class Names

But if I change the last sentence to: n.getList().forEach(n::printNames);

then it does compile.

So the reason why it doesn't compile is not only that the forEach method requires a method that takes an argument. Correct me if I am wrong.

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

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

Post by admin » Sat Jun 24, 2017 8:57 pm

Yes, that could also be a valid reason.
If you like our products and services, please help us by posting your review here.

__JJ__
Posts: 125
Joined: Thu Jul 05, 2018 6:44 pm
Contact:

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

Post by __JJ__ » Thu Jul 26, 2018 6:07 pm

I think this is quite an important concept.
We have learnt from other questions that you can supply a INSTANCE method reference of the form X::foo, where foo takes no parameters, as an argument to a method (call it bar) that expects a method that takes a parameter, and the compiler is smart enough to recognise that an instance of X will be the required parameter, but it only works if what's going into bar is the same type as X.
That sounds a bit like gobbledegook but I can see now why this works:

Code: Select all

       n.getList().forEach(String::toString);
but this doesn't

Code: Select all

      n.getList().forEach(Names::printNames);
ie it's because getList supplies a String; so you can either supply any method reference X::xyz where xyz takes a String or you can supply a reference to a no-arg instance method of String in which String becomes the required argument corresponding to apply(T t).
Of course you could supply any one-arg static method that takes a String also.

Post Reply

Who is online

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