0

I am trying out few things related to method references using functional interfaces. I wanted to convert a string into the upper case using a bounded receiver and an unbounded receiver. Although I have understood print1 and print2 methods, I am not sure how the print3 compiles. Because Consumer has the void accept(T t); which takes a single argument and returns nothing, whereas toUpperCase() in String class takes no argument but returns a String. I guess the compiler just checks if the actual argument is a lambda expression/MR and the formal parameter is a Functional Interface. Is it correct?

package com.learn.boundedtypes;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
public class MRTest
{
   public static void main(String[] args)
   {
      String s = "The quick brown fox jumped over the lazy dog";
      print1(s::toUpperCase);
      print2(String::toUpperCase, s);
      print3(String::toUpperCase, s);
      
   }
   public static void print1(Supplier<String> supplier)
   {
      System.out.println(supplier.get());
   }
   
   public static void print2(Function<String, String> function, String s)
   {
      System.out.println(function.apply(s));
   }
   
   public static void print3(Consumer<String> consumer, String s)
   {
      consumer.accept(s);
      System.out.println(s);
   }
} 

Output:

THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG
THE QUICK BROWN FOX JUMPED OVER THE LAZY DOG
The quick brown fox jumped over the lazy dog
skgv
  • 47
  • 1
  • 3
  • 3
    `String::toUpperCase` doesn't take an argument, which should theoretically already be a problem for `print2`, since a `Function` requires an argument, but the instance itself is automagically used as "the argument". The same magic allows `String::toUpperCase` to be a `Consumer` by simply calling `toUpperCase` on the instance and ignoring the return value (which explains why the third output is not upper-cased: by ignoring the return value the call to `toUpperCase` becomes pointless). – Joachim Sauer Mar 16 '21 at 15:03
  • @JoachimSauer your comment should be converted to an answer – Alex Sveshnikov Mar 16 '21 at 15:05
  • @Alex: I was thinking about it, but it doesn't quite meet my own quality bar, since I'd want to quote the relevant rules and I don't have time for that atm. Feel free to post it as an answer yourself ;-) – Joachim Sauer Mar 16 '21 at 15:06
  • @JoachimSauer Thanks for your response. Is it not confusing when we have to decide if a particular method reference "fits into" a particular Functional Interface or not? – skgv Mar 16 '21 at 15:15
  • 1
    As far as I know the rules where designed to "just work". In other words: if there is a reasonable way to interpret the method reference as implementing the functional interface, then it'll be allowed. The real rules are of course much more complex (and more specific) than this, but that was the likely one of the design goals and I think they've met it nicely. – Joachim Sauer Mar 16 '21 at 15:29
  • 1
    JLS, [15.3.1 Compile-Time Declaration of a Method Reference](https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.13): A method reference ReferenceType :: [TypeArguments] Identifier can be interpreted in different ways. If Identifier refers to an instance method, then the implicit lambda expression has an extra parameter compared to if Identifier refers to a static method. It is possible for ReferenceType to have both kinds of applicable methods, so the search algorithm described above identifies them separately, since there are different parameter types for each case. – Alex Sveshnikov Mar 16 '21 at 15:45
  • @Alex Thanks for taking your time and sharing it. I will take a look. – skgv Mar 16 '21 at 15:51

0 Answers0