I don't understand how to use lambdas to pass a method as a parameter.
Considering the following (not compiling) code, how can I complete it to get it work ?
public class DumbTest {
public class Stuff {
public String getA() {
return "a";
}
public String getB() {
return "b";
}
}
public String methodToPassA(Stuff stuff) {
return stuff.getA();
}
public String methodToPassB(Stuff stuff) {
return stuff.getB();
}
//MethodParameter is purely used to be comprehensive, nothing else...
public void operateListWith(List<Stuff> listStuff, MethodParameter method) {
for (Stuff stuff : listStuff) {
System.out.println(method(stuff));
}
}
public DumbTest() {
List<Stuff> listStuff = new ArrayList<>();
listStuff.add(new Stuff());
listStuff.add(new Stuff());
operateListWith(listStuff, methodToPassA);
operateListWith(listStuff, methodToPassB);
}
public static void main(String[] args) {
DumbTest l = new DumbTest();
}
}
4 Answers 4
Declare your method to accept a parameter of an existing functional interface type which matches your method signature:
public void operateListWith(List<Stuff> listStuff, Function<Stuff, String> method) {
for (Stuff stuff : listStuff) {
System.out.println(method.apply(stuff));
}
}
and call it as such:
operateListWith(listStuff, this::methodToPassA);
As a further insight, you don't need the indirection of methodToPassA:
operateListWith(listStuff, Stuff::getA);
5 Comments
listStuff.stream().map(method).forEach(System.out::println)? Isn't that the entire point of lambdas?<Stuff, String> in fact. Fixed.Your MethodParameter should be some interface you define with a single method. This is referred to as a functional interface. You can then pass your methods in. A quick demonstration:
public interface Test{
void methodToPass(string stuff);
}
[...]
public class DumbTest{
//MethodParameter is purely used to be comprehensive, nothing else...
public void operateListWith(List<Stuff> listStuff, Test method) {
for (Stuff stuff : listStuff) {
System.out.println(method(stuff));
}
}
public DumbTest() {
List<Stuff> listStuff = new ArrayList<>();
//fill list
operateListWith(listStuff, methodToPassA);
operateListWith(listStuff, methodToPassB);
}
}
Comments
The definition of MethodParameter is missing from your source code. To be used with lambda expressions, it must be a functional interface, for example:
@FunctionalInterface
interface MethodParameter {
String apply(Stuff input);
}
(The @FunctionalInterface annotation is optional.)
To use the method, you have call the method from the interface:
System.out.println(method.apply(stuff));
And thirdly, a method reference always needs a context. In your case you have to do:
operateListWith(listStuff, this::methodToPassA);
operateListWith(listStuff, this::methodToPassB);
Comments
You need to use method references.
You don't need to create a method like operateListWith, that's sort of the whole idea. Instead, you can operate on each value using forEach by doing something like this:
listStuff.stream.forEach(object::methodToPassA);
For example:
public class StreamExample {
public static void main(String[] args) {
List<String> list = Arrays.asList("Hello", "What's Up?", "GoodBye");
list.stream().forEach(System.out::println);
}
}
Output:
Hello
What's Up?
GoodBye
In your case, you can get the value inside Stuff using .map, and then operate on it using forEach, like this:
public class DumbTest {
public class Stuff {
public String getA() {
return "a";
}
public String getB() {
return "b";
}
}
public String methodToPassA(Stuff stuff) {
return stuff.getA();
}
public String methodToPassB(Stuff stuff) {
return stuff.getA();
}
public DumbTest() {
List<Stuff> listStuff = Arrays.asList(new Stuff(), new Stuff());
listStuff.stream()
.map(this::methodToPassA)
.forEach(System.out::println);
}
public static void main(String[] args) {
DumbTest l = new DumbTest();
}
}
interfacewith only 1 method, likeRunnable). I do not see you declaring a functional interface. Also, when you get an error, tell us what error you are getting and where it's at.