Reputation:
I am reading a Lambda example from Herbert Shildt book- Java the complete reference. The code is written in side of LambdasAsArgumentsDemo.java file
interface StringFunc {
String func(String n);
}
class LambdasAsArgumentsDemo {
public static void main(String args[]){
String inStr = "Lambdas add power to Java";
String outStr;
// Here, a simple expression lambda that uppercases a string is passed to stringOp( ).
outStr = stringOp((str) -> str.toUpperCase(), inStr);
System.out.println("The string in uppercase: " + outStr);
//This method has a functional interface as the type of its
// first parameter. Thus, it can be passed a reference to
//any instance of that interface, including the instance
//created by a lambda expression.
//The second parameter specifies the string to operate on.
static String stringOp(StringFunc sf, String s) {
return sf.func(s);
}
}
Now my question is at the line
outStr = stringOp((str) -> str.toUpperCase(), inStr);
How come it is true that when you pass (str) -> str.toUpperCase()
as argument, an instance of the functional interface StringFunc
is created and a reference to that object is passed as the
first parameter of stringOp()
?? How does it know to instantiate StringFunc
?
Upvotes: 1
Views: 71
Reputation: 59208
StringFunc
defines an interface for a function which takes a string as argument and returns a string. Your lambda expression (str) -> str.toUpperCase()
does the same. It takes a string ((str)
and returns a string (str.toUppercase()
), so it matches the interface.
Think like this: there's no need to instantiate an object of that interface, since the lambda already is the instance. It's sufficient to cast it to the interface. str
would then be the name of the argument.
You can achieve the same result by using a regular method with that signature:
public static void main(String args[]){
String inStr = "Lambdas add power to Java";
String outStr;
outStr = stringOp(LambdasAsArgumentsDemo::mymethod, inStr);
System.out.println("The string in uppercase: " + outStr);
}
public static String mymethod(String str) { return str.toUpperCase(); }
^ ^ ^
| | implementation
| String argument called str
String return type
From the comments:
BTW, I have some other related question. What if there is similar 2 other functional interfaces like interface StringFunc2 { String func2(String n); } and interface StringFunc3 { String func3(int n); } In such case, how would it get resolved ? What is the explanation ? BTW, it is still compiling OK and producing the same output.
The code calls stringOp()
. stringOp()
takes either StringFunc
, StringFunc2
or StringFunc3
. So the compiler knows at compile time, which one to choose.
If, however, you define three interfaces and three functions, the code cannot compile and fails with an error message that the call is ambiguous, because the lambda could be either one.
import java.util.*;
import java.lang.*;
import java.io.*;
interface StringFunc {
String func(String n);
}
interface StringFunc2 {
String func(String n);
}
interface StringFunc3 {
String func(String n);
}
class LambdasAsArgumentsDemo {
public static void main(String args[]){
String inStr = "Lambdas add power to Java";
String outStr;
outStr = stringOp((str) -> str.toUpperCase(), inStr);
System.out.println("The string in uppercase: " + outStr);
}
static String stringOp(StringFunc sf, String s) {
return sf.func(s);
}
static String stringOp(StringFunc2 sf, String s) {
return sf.func(s)+"2";
}
static String stringOp(StringFunc3 sf, String s) {
return sf.func(s)+"3";
}
}
Upvotes: 2