How to pass argument to class constructor on initialization via :: new in Java8
I am using java 8 stream API to perform actions on a list of objects Store
.
Store
takes an argument String
and an object Mapper
. Mapper
will be the same for all objects Store
.
Question: How to pass an object Mapper
on initialization Store
here .map(Store::new)
?
public class Store {
public Store(String name, Mapper mapper) {
}
}
public class Mapper {
}
public class Test {
public static void main(String[] args) {
List<String> names = new ArrayList<String>();
Mapper mapper = new Mapper();
// compile time problem at Store::new because it takes 2 arguments
List<Store> actions =
names.stream()
.map(Store::new)
.collect(Collectors.toList());
}
}
source to share
You cannot use a method reference for a constructor that needs to get a free variable, that is, a variable from the context.
Refer to the Java Tutorial, Section Method References for more information on method references.
You can use a lambda expression instead:
Mapper mapper = new Mapper();
List<Store> actions =
names.stream()
.map(name -> new Store(name, mapper))
.collect(Collectors.toList());
If for any reason you insist on using a method reference, you can still , although the solution is more complex and cumbersome . In fact, it is much better from all possible points of view to use a lambda expression instead of what I describe below. I am writing this simply to show that method references are only good if you already have a method or constructor whose signature matches what is expected.
Suppose you have declared this helper method:
public static <T, U, R> Function<T, R> bindSecond(
BiFunction<T, U, R> biFunction,
U free) {
return t -> biFunction.apply(t, free);
}
Here I create and return a function with 1 argument that applies only one argument to a given bifurc (function with two arguments) and also a given free variable. In other words, I bind the given free variable to the given bfunction as my second argument.
Your example Store::new
is actually a binary that takes two arguments ( name
and mapper
) and returns a value (new instance Store
), and you get this compilation error because you Stream.map
expect a 1-argument function that takes a stream element as the only parameter.
The helper method bindSecond
actually converts the given bifunction and free variable into a function with one argument that matches the method signature Stream.map
.
You can use it like this:
Mapper mapper = new Mapper();
List<Store> actions =
names.stream()
.map(bindSecond(Store::new, mapper))
.collect(Collectors.toList());
But again, I see no point in using this over a simple lambda expression .
source to share