为什么供应商只支持no-arg构造函数?
如果存在默认构造函数,我可以这样做:
create(Foo::new)
但是如果唯一的构造函数采用String,我必须这样做:
create(() -> new Foo("hello"))
答案 0 :(得分:49)
但是,T
的1-arg构造函数需要String
与Function<String,T>
兼容:
Function<String, Foo> fooSupplier = Foo::new;
根据目标类型的形状,选择哪个构造函数被视为重载选择问题。
答案 1 :(得分:47)
这只是方法参考语法的限制 - 您无法传递任何参数。这就是语法的工作原理。
答案 2 :(得分:37)
如果您非常喜欢方法引用,可以自己编写bind
方法并使用它:
public static <T, R> Supplier<R> bind(Function<T,R> fn, T val) {
return () -> fn.apply(val);
}
create(bind(Foo::new, "hello"));
答案 3 :(得分:10)
为什么供应商只使用无参数构造函数?
因为1-arg构造函数与具有1个参数和1个返回值的SAM接口同构,例如java.util.function.Function<T,R>
的{{1}}。
另一方面,R apply(T)
的{{1}}与零arg构造函数同构。
它们根本不兼容。您的Supplier<T>
方法需要是多态的,以接受各种功能接口,并根据提供的参数采取不同的行动,或者您必须编写一个lambda主体作为两个签名之间的粘合代码。
这里你未满足的期望是什么?您认为应该发生什么?
答案 4 :(得分:9)
The Supplier<T>
interface represents a function with a signature of () -> T
, meaning it takes no parameters and returns something of type T
. Method references that you provide as arguments must follow that signature in order to be passed in.
If you want to create a Supplier<Foo>
that works with the constructor, you can use the general bind method that @Tagir Valeev suggests, or you make a more specialized one.
If you want a Supplier<Foo>
that always uses that "hello"
String, you could define it one of two different ways: as a method or a Supplier<Foo>
variable.
method:
static Foo makeFoo() { return new Foo("hello"); }
variable:
static Supplier<Foo> makeFoo = () -> new Foo("hello");
You can pass in the method with a method reference(create(WhateverClassItIsOn::makeFoo);
), and the variable can be passed in simply using the name create(WhateverClassItIsOn.makeFoo);
.
The method is a little bit more preferable because it is easier to use outside of the context of being passed as a method reference, and it's also able to be used in the instance that someone requires their own specialized functional interface that is also () -> T
or is () -> Foo
specifically.
If you want to use a Supplier
that can take any String as an argument, you should use something like the bind method @Tagir mentioned, bypassing the need to supply the Function
:
Supplier<Foo> makeFooFromString(String str) { return () -> new Foo(str); }
You can pass this as an argument like this: create(makeFooFromString("hello"));
Although, maybe you should change all the "make..." calls to "supply..." calls, just to make it a little clearer.
答案 5 :(得分:1)
在寻找参数化Supplier
问题的解决方案时,我发现上述答案很有帮助,并提出了建议:
private static <T, R> Supplier<String> failedMessageSupplier(Function<String,String> fn, String msgPrefix, String ... customMessages) {
final String msgString = new StringBuilder(msgPrefix).append(" - ").append(String.join("\n", customMessages)).toString();
return () -> fn.apply(msgString);
}
它是这样调用的:
failedMessageSupplier(String::new, msgPrefix, customMsg);
我对丰富的静态函数参数还不太满意,我进一步研究了Function.identity(),得出以下结果:
private final static Supplier<String> failedMessageSupplier(final String msgPrefix, final String ... customMessages) {
final String msgString = new StringBuilder(msgPrefix).append(" - ").append(String.join("\n", customMessages)).toString();
return () -> (String)Function.identity().apply(msgString);
};
现在没有静态函数参数的调用:
failedMessageSupplier(msgPrefix, customMsg)
由于Function.identity()
返回的类型为Object
的函数,随后的apply(msgString)
调用也是如此,因此需要强制转换为String
-或任何类型, apply()被喂饱了。
此方法允许e。 G。使用多个参数,动态字符串处理,字符串常量前缀,后缀等。
从理论上讲,使用身份也应比String :: new略有优势,它将始终创建一个新字符串。
正如Jacob Zimmerman所指出的那样,更简单的参数化形式
Supplier<Foo> makeFooFromString(String str1, String str2) {
return () -> new Foo(str1, str2);
}
总是可能的。在上下文中这是否有意义取决于情况。
如上所述,静态方法引用调用需要相应方法的数量和返回/参数的类型,以与使用函数(流)的方法所期望的相匹配。
答案 6 :(得分:0)
将供应商与FunctionalInterface配对。
这里是一些示例代码,我将它们放在一起,用于演示“绑定”带有Function的特定构造函数的构造函数引用,以及定义和调用“工厂”构造函数引用的不同方法。
30-36MB
答案 7 :(得分:0)
如果您有new Klass(ConstructorObject)
的构造函数,则可以像这样使用Function<ConstructorObject, Klass>
:
interface Interface {
static Klass createKlass(Function<Map<String,Integer>, Klass> func, Map<String, Integer> input) {
return func.apply(input);
}
}
class Klass {
private Integer integer;
Klass(Map<String, Integer> map) {
this.integer = map.get("integer");
}
public static void main(String[] args) {
Map<String, Integer> input = new HashMap<>();
input.put("integer", 1);
Klass klazz = Interface.createKlass(Klass::new, input);
System.out.println(klazz.integer);
}
}