在Java8中通过::new初始化时如何将参数传递给类构造函数 [英] How to pass argument to class constructor when initialzed thru ::new in Java8
问题描述
我正在使用 java 8 流 API 对 Store
对象列表执行操作.
I am using java 8 stream API to perform action on a list of Store
objects.
Store
接受一个 String
参数和一个 Mapper
对象.Mapper
对于所有 Store
对象都是相同的.
Store
takes a String
argument and a Mapper
object. Mapper
will be same for all Store
object.
问题:当我在 .map(Store::new)
初始化 Store
时如何传递 Mapper
对象?
Question: How can I pass Mapper
object when I initialize 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());
}
}
推荐答案
对于需要接收自由变量(即来自上下文的变量)的构造函数,您不能使用方法引用.
You can't use a method reference for a constructor that needs to receive a free variable, i.e. a variable from the context.
请参阅Java 教程,方法参考部分查找有关方法引用的更多信息.
Please refer to the Java Tutorial, section Method References to find more info about method references.
您可以改用 lambda 表达式:
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());
如果出于某种原因,您坚持使用方法引用,您仍然可以,虽然解决方案更加复杂和麻烦.事实上,从所有可能的角度来看,使用 lambda 表达式而不是我在下面介绍的 hack 要好得多.我写它只是为了表明只有当你已经有一个签名与预期匹配的方法或构造函数时,方法引用才是好的.
If, for whatever reason, you insist on using a method reference, you still can, though the solution is more complex and cumbersome. In fact, it's much better from all possible points of view to use a lambda expression instead of the hack I'm introducing below. I'm writing it just to show that method references are good only if you already have a method or constructor whose signature matches the expected one.
假设你声明了这个辅助方法:
Suppose you declare 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);
}
在这里,我正在创建并返回一个 1 参数函数,该函数将其唯一一个参数应用于给定的双函数(2 参数函数)以及给定的自由变量.换句话说,我将给定的自由变量绑定到给定的双函数作为它的第二个参数.
Here I'm are creating and returning a 1-argument function that applies its only one argument to the given bifunction (a 2-argument function), as well as the given free variable. In other words, I'm binding the given free variable to the given bifunction as its second argument.
在您的示例中,Store::new
实际上是一个双函数,它接受两个参数(name
和 mapper
)并返回一个值(新的 Store
实例),并且您会收到该编译错误,因为 Stream.map
需要一个 1-argument 函数,该函数将流的元素作为其唯一一个参数.
In your example, Store::new
is actually a bifunction that takes two arguments (name
and mapper
) and returns a value (the new Store
instance), and you are getting that compilation error because Stream.map
expects a 1-argument function that takes the element of the stream as its only one parameter.
bindSecond
辅助方法实际上将给定的双函数和自由变量转换为与 Stream.map
方法的签名相匹配的单参数函数.
The bindSecond
helper method actually transforms the given bifunction and free variable into a 1-argument function that matches the signature of the Stream.map
method.
你可以这样使用它:
Mapper mapper = new Mapper();
List<Store> actions =
names.stream()
.map(bindSecond(Store::new, mapper))
.collect(Collectors.toList());
但是,我认为在简单的 lambda 表达式上使用它没有意义.
这篇关于在Java8中通过::new初始化时如何将参数传递给类构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!