About Question enthuware.ocpjp.v8.2.1871 :

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

Moderator: admin

Post Reply
johnlong
Posts: 197
Joined: Mon Jun 20, 2016 5:06 pm
Contact:

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

Post by johnlong »

Got it
process(fnames, t::eat); -> process( fnames, a -> t.eat(a));
process(fnames, t::calories); -> process( fnames, a -> t.calories(a));
process(fnames, TestClass::size); -> process( fnames, a -> TestClass.size(a));

Q1) So how to differentiate between var::instanceMethod or class:instanceMethod?
Q2) Lambda expression for var::instanceMethod and class:StaticMethod has the same syntax?

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

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

Post by admin »

johnlong wrote: Q1) So how to differentiate between var::instanceMethod or class:instanceMethod?
Q2) Lambda expression for var::instanceMethod and class:StaticMethod has the same syntax?
Not sure what you mean by differentiation. var::instanceMethod uses the variable name, while class:instanceMethod uses the class name.


It is explained here is more detail: https://docs.oracle.com/javase/tutorial ... ences.html
If you like our products and services, please help us by posting your review here.

johnlong
Posts: 197
Joined: Mon Jun 20, 2016 5:06 pm
Contact:

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

Post by johnlong »

Thanks.

ramy6_1
Posts: 124
Joined: Wed Feb 12, 2014 2:44 am
Contact:

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

Post by ramy6_1 »

Hello ,

I have the same above question as I still have problems understanding method and constructor reference

Could you please advise how can I substitute those method references with the lambda expressions?

process(fnames, t::eat);
process(fnames, t::calories);
process(fnames, TestClass::size);

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

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

Post by admin »

Check out this article: http://enthuware.com/index.php/home/115
Now, look at the method eat, for example, and turn it into a lambda expression as described in above article.
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.1871 :

Post by lenalena »

I'm having trouble understanding the explanation for why last option (Tiger::eat) is wrong. I understand the situation with the static reference. However, the part
"Which meaning is implied depends on the context in which it is used. Here, the context does not supply any instance of Tiger class.
How DOES the context supply the instance of Tiger class in this situation? It's clear when the method reference is called on an instance variable (such as t::eat). But in case of Tiger::eat - how would the instance of Tiger class be supplied by the context. Could you, please, show an example?

Thank you.

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

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

Post by admin »

The object is supplied by the context if it is available in the context. For example,

Code: Select all

String[] stringArray = { "Barbara", "James", "Mary", "John",
    "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);
(Ref: https://docs.oracle.com/javase/tutorial ... ences.html )
The compareToIgnoreCase method has to operate on the stringArray. So the context does have String objects in that array. Therefore, it can supply two strings from the array to call that method. There is no need for a separate String object for the method to be invoked.

In the last option of this question, process(fnames, Tiger::eat);, there is no Tiger object in the context.

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

ssoltanid
Posts: 3
Joined: Wed Nov 12, 2014 3:03 pm
Contact:

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

Post by ssoltanid »

Hi, I'm pretty sorry but I couldn't understand the answer at all.

How this line :

Code: Select all

process(fnames, t::calories);
can call this method :

Code: Select all

public static void process(List<String> names, Carnivore c) {
        c.eat(names);
    }
Since the method's waiting for 2 args : List<String> names and Carnivore c.

In fact I couldn't understand how we can pass t::calories to Carnivore c, since t:calories return a int.

Sorry about the question.

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

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

Post by admin »

Carnivore has only one abstract method "int eat(List<String> foods)".
To implement this interface using a lambda expression, you require a reference to a method with the same parameter and return types. t::calories refers to Carnivore's default method "int calories(List<String> food)", which satisfies this requirement. So there is no issue.
If you like our products and services, please help us by posting your review here.

zukras
Posts: 5
Joined: Fri Jun 02, 2017 4:57 pm
Contact:

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

Post by zukras »

Tiger::eat is a valid method reference that can mean to refer either to a static method eat of Tiger class or to an instance method of any arbitrary instance of Tiger class. Which meaning is implied depends on the context in which it is used. Here, the context does not supply any instance of Tiger class.
How would look like context where I could call Tiger::eat?

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

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

Post by admin »

Let's say you have this interface:

Code: Select all

interface SomeI{
  void m(Tiger t, List<String> list);
}
You can then do the following in the main of TestClass:

Code: Select all

class TestClass{
  public static void main(String[] args) {
      SomeI s = Tiger::eat;
  }
}
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.1871 :

Post by __JJ__ »

Martyjee wrote:
Thu Oct 15, 2015 3:51 am
Hi Paul,
As per the code that is given, if you use Tiger::eat, you are implying that you want to call eat method on Tiger class (as opposed to Tiger instance)
No, that is not true, you are implying that you want to use the code that is defined in the eat method of the type Tiger! The Oracle docs define 4 flavours of method references, and this flavour (the most confusing one) is what they call "Reference to an Instance Method of an Arbitrary Object of a Particular Type". Remember that we are dealing with lambda expressions and method references here, not actual method calls!
There is no context here that provides you a Tiger instance.
You don't need a Tiger instance, and the eat method does not have to be static to reference it as Tiger::eat.
Could you please show with code what you mean?
I will give a code example that I came up with (assume appropriate import statements):

Code: Select all

public class Example {
    public static void main(String[] args) {
        Mother mother = new Mother();
        Child child = new Child();
        mother.giveOrder(child::eat);   //1 Reference to an instance method of a particular object
        mother.giveOrder(Knife::slice); //2 Reference to an instance method of an arbitrary object of a particular type
        mother.giveOrder(Knife::stab);  //3 Reference to a static method
    }
}
[SNIP]
    }
}
As you can see at line //2 there is no instance needed to reference Knife::slice
It compiles fine! The context is created at line //4 where the actual Knife object is first needed!
It looks like the "slice" method does not have the required parameters to be treated as an Eater, but actually it does, because the compiler inserts some arbitrary object reference to the parameter list as its first parameter! The program will even cause a compilation error at //2 if we rename the method "stab" to "slice", because their parameter lists are effectively the same when used as a lambda expression!!

HTH,

Martijn
Have to say, this is very clever. I have been looking at it and having a play and it's quite something how it manages to work.
I think it could be one of those things that once you used it a number of times you'd just see it as normal, but when you first come across it, it's a bit of a head scratcher. But thank you for putting together this example. I suggest people have a play with it themselves and reduce it down to just the interesting stuff ie the stuff pertinent to

Code: Select all

mother.giveOrder(Knife::slice);

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

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

Post by __JJ__ »

After playing around with Martijn's code, I was able to hack the code in the question to get it to work with the Tiger::eat method reference; not to prove the question/answer wrong (it's not, as far as I can see) but just to try to get a handle on how Martijn's example works.
So FWIW here it is

Code: Select all

import java.util.function.*;
import java.util.*;

interface Carnivore{
    default int calories(List<String> food){
        return food.size()*100;
    }
    int eat(Tiger t, List<String> foods);
}
class Tiger { 
    public int eat(List<String> foods){
        System.out.println("Eating "+foods);
        return foods.size()*200;
    }
}
public class TestClass4 {
    public static int size(List<String> names){
        return names.size()*2;
    }
    public static void process(List<String> names, Carnivore c){
        c.eat(new Tiger(), names);
    }
    
    public static void main(String[] args) {
        List<String> fnames = Arrays.asList("a", "b", "c");
        process(fnames, Tiger::eat);

   }
}
The key thing it seems is that the interface method has to have as an (its first?) argument the class type of the instance that will be supplied at runtime. That type must have a method that takes the rest of the arguments defined in the interface's abstract method (here, just one extra argument). Then at runtime the invocation of the functional interface method will supply an instance

Code: Select all

c.eat(new Tiger(), names);
and that instance is what the instance method is invoked on.
It really is very clever.

Sorry if any of this is wrong; I'm just trying to understand it myself and thought it might help somebody.

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

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

Post by tylrdr »

__JJ__ wrote:
Fri Jul 27, 2018 7:27 pm
After playing around with Martijn's code, I was able to hack the code in the question to get it to work with the Tiger::eat method reference
Thank you for the example.

To make it even more understandable, in your example process(fnames, Tiger::eat) can be replaced with:

1) This equivalent lambda:
process(fnames, (a,b)->a.eat(b));

2) Or this equivalent anonymous class:
process(fnames, new Carnivore(){
@Override
public int eat(Tiger t, List<String> foods) {
return t.eat(foods);
}
});

It clearly works but I can't find any rule that explains why it works like this and how it works exactly. If anyone can figure out what the rule is about how exactly Java finds "context", would be helpful.
Admin said "The object is supplied by the context if it is available in the context." Sadly I don't quite understand this because the word context is too abstract for me... can anyone define "context" or is there a better way to describe this behavior please?

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

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

Post by admin »

Exact and complete rules are given in Section 15.13 of JLS 11.
If you like our products and services, please help us by posting your review here.

Post Reply

Who is online

Users browsing this forum: No registered users and 14 guests