Syntax for specifying a method reference to a generic method
Asked Answered
S

3

13

I read the following code in "Java - The beginner's guide"

interface SomeTest <T>
{
    boolean test(T n, T m);
}

class MyClass
{
    static <T> boolean myGenMeth(T x, T y)
    {
        boolean result = false;
        // ...
        return result;
    }
}

The following statement is valid

SomeTest <Integer> mRef = MyClass :: <Integer> myGenMeth;

Two points were made regarding the explanation of the above code

1 - When a generic method is specified as a method reference, its type argument comes after the :: and before the method name.

2 - In case in which a generic class is specified, the type argument follows the class name and precedes the ::.

My query:-

The code above is the example of the first quoted point

Can someone provide me an example of code which implement the second quoted point?

(Basically I don't understand the second quoted point).

Saddlery answered 6/7, 2015 at 11:50 Comment(7)
This code does not compile.Syriac
@ChetanKinger : This code will not compile as it is. First you have to add a main class in it and then put SomeTest <Integer> mRef = MyClass :: <Integer> myGenMeth; in that main classSaddlery
Please post MVC code sample. As far I know, it won't compile even after we do what you said in the previous comment.Syriac
@kevingomes, unfortunately the accepted answer from Keppil is probably still not correct in the context of your actual question. While that is one form of method reference, it probably isn't what the book means in that quote.Fumigator
@AndyBrown :please post the correct answer then.Saddlery
@kevingomes. I was about to, but noticed that bayou.io already did.Fumigator
@AndyBrown : Can you please tell me the difference between both the answer.Saddlery
E
2

The second quoted point just means that the type parameter belongs to the class. For example:

class MyClass<T>
{
    public boolean myGenMeth(T x, T y)
    {
        boolean result = false;
        // ...
        return result;
    }
}

This would then be called like this:

SomeTest<Integer> mRef = new MyClass<Integer>() :: myGenMeth;
Engels answered 6/7, 2015 at 11:58 Comment(16)
why can't I add static before boolean myGenMeth(T x, T y);Saddlery
static would turn the method into a class method instead of an instance method. Since you have to create an instance of the class to set the type parameter here, you can't declare a static method that uses the generic class type parameter.Engels
dude, your code isn't working; I used SomeTest <Integer> mRef = MyClass <Integer> :: genMeth;Saddlery
@kevingomes It won't work because you don't have OtherClass. Keppil was hyst giving you an example. Change it to Integer :)Syriac
@ChetanKinger : I am using Integer, still it is not workingSaddlery
@ChetanKinger @keppil : Giving error in every case : Non static method myGenMeth <T,T> can not be referenced from a static contextSaddlery
@kevin: Fixed the calling part.Engels
great effort. But please include the difference between your current answer and your previous answer. Why it was not working as per your previous answer?Saddlery
The mistake I made was not remembering to create an instance of the class to use when referencing the method. I even touched on it in my comment above, but didn't see the error in the code I posted. My bad.Engels
@kevingomes You really need to make up your mind about what your question is. Are you asking Why does my code not compile?Syriac
@ChetanKinger : Read my question carefully. I, in very simple words, asked the meaning of the second quoted point in my question.Saddlery
@kevingomes but does point 1 even compile? I don't have Java -8 here on my machine to confirm this.Syriac
@ChetanKinger : Yes, just add, class Main{ public static void main(String args[]) { SomeTest <Integer> mRef = MyClass :: <Integer> myGenMeth;} }Saddlery
@ChetanKinger : Now you came to the point. This feature is only supported in java-8Saddlery
@kevingomes Lol. I know it's only available in Java-8. What I am asking is does it compile in Java-8. Nevermind though. If it compiles for you then i am fine with it :)Syriac
@Engels : Can you please tell me the difference between your answer and bayou.io's answerSaddlery
B
2

For example

  Predicate<List<String>> p = List<String>::isEmpty;

Actually we don't need the type argument here; the type inference will take care of

  Predicate<List<String>> p = List::isEmpty;

But in cases type inference fails, e.g. when passing this method reference to a generic method without enough constraints for inference, it might be necessary to specify the type arguments.

Brittaney answered 6/7, 2015 at 15:6 Comment(2)
can you please tell me the difference between your answer and Keppil's answerSaddlery
@Keppil unnecessarily constructs an instance of MyClass.Eld
E
0

I'm also learning from that book (Java The Complete Reference Twelfth Edition)

The only way i understood the second quote, its in the code below:

interface FuncInterf<O, T>
{
    int func(O op, T[] arr, T val);
}

class Operations<T>
{
    int countMatches(T[] arr, T val)
    {
      int counter = 0;

      for(int i=0; i<arr.length; i++)
        if(arr[i] == val)
          counter++;

      return counter;
    }
}

public class Main
{
    static <O, T> int methRef(FuncInterf<O, T> fI, O op, T[] arr, T val)
    {
      return fI.func(op, arr, val);
    }

    public static void main(String[] args)
    {
      Integer[] iArr = {1, 2, 3, 4, 3, 5};
      int iVal = 3;
      int matches = 0;

      FuncInterf<Operations<Integer>, Integer> fI = Operations<Integer>::countMatches;
      matches = methRef(fI, new Operations<Integer>(), iArr, iVal);

      System.out.println("Total of " + iVal + "'s: " + matches);
  }
}

The interesting part is that, an extra type parameter (letter 'O') on interface FuncInterface <O, T> and also, an extra parameter (O op) on method func is needed to be able to reference the method countMatches and do what the book says:

In cases in which a generic class is specified, the type argument follows the class name and precedes the ::

Which is: Operations<Integer>::countMatches;

The reason that O op is created its because it will be the object thats going to call/reference countMatches method from methRef method in return fI.func(op, arr, val);

O will be type Operations<T>, and <T> Integer in this example. Resulting in Operations<Integer>

This kind of method reference its a 'Reference to instance method of an arbitrary object of a given type'. The method (countMatches) thats implementing Functional Interface's SAM (Single Abstract Method) doesn't need to have an extra parameter O op, because actually op its "indirectly" calling countMatches

Enfeoff answered 13/6, 2024 at 3:32 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.