为什么供应商仅支持无参数构造函数?
如果存在默认构造函数,则可以执行以下操作:
create(Foo::new)
但是,如果唯一的构造函数采用字符串,则必须这样做:
create(() -> new Foo("hello"))
为什么供应商仅支持无参数构造函数?
如果存在默认构造函数,则可以执行以下操作:
create(Foo::new)
但是,如果唯一的构造函数采用字符串,则必须这样做:
create(() -> new Foo("hello"))
Supplier 不使用lambda表达式时工作,提供的参数,即。因此,您的实际问题似乎是“为什么仅当功能参数与目标参数匹配时方法引用才起作用”,答案是,因为这就是方法引用的目的。如果参数列表不匹配,请使用问题中已显示的lambda表达式。因为那是lambda表达的目的(不是唯一的)……
                Answers:
该Supplier<T>接口与代表的签名功能() -> T,这意味着它不带任何参数和返回类型的东西T。您作为参数提供的方法引用必须跟随该签名才能传递。
如果要创建一个Supplier<Foo>可与构造函数一起使用的,则可以使用@Tagir Valeev建议的常规bind方法,或者您可以使用更专门的方法。
如果要Supplier<Foo>始终使用该"hello"String,则可以使用两种不同的方式之一对其进行定义:作为方法或Supplier<Foo>变量。
方法:
static Foo makeFoo() { return new Foo("hello"); }
变量:
static Supplier<Foo> makeFoo = () -> new Foo("hello");
您可以使用方法reference(create(WhateverClassItIsOn::makeFoo);)传入该方法,并且只需使用name即可传入该变量create(WhateverClassItIsOn.makeFoo);。
该方法是多一点点可取,因为它更容易使用的方法引用传递的背景之外,它也能够在实例中使用的是有人需要自己专门的功能接口,这也是() -> T或() -> Foo专门。
如果要使用Supplier可以将任何String用作参数的a,则应使用类似提及的bind方法@Tagir之类的方法,而无需提供Function:
Supplier<Foo> makeFooFromString(String str) { return () -> new Foo(str); }
您可以将其作为这样的参数传递: create(makeFooFromString("hello"));
虽然,也许您应该将所有的“ make ...”调用更改为“ supply ...”调用,以使其更加清晰。
为什么供应商仅与无参数构造函数一起使用?
因为1-arg构造函数与具有1个参数和1个返回值(例如的)的SAM接口是同构java.util.function.Function<T,R>的R apply(T)。
另一方面Supplier<T>,T get()它与零arg构造函数同构。
它们根本不兼容。您的create()方法需要是多态的,以接受各种功能接口,并根据提供的参数而有所不同,或者您必须编写一个lambda主体以充当两个签名之间的粘合代码。
您在这里的未满足期望是什么?什么应该在您看来怎样?
将供应商与FunctionalInterface配对。
这是一些示例代码,我将它们汇总在一起以演示使用Function将构造函数引用“绑定”到特定构造函数的方法,以及定义和调用“工厂”构造函数引用的不同方法。
import java.io.Serializable;
import java.util.Date;
import org.junit.Test;
public class FunctionalInterfaceConstructor {
    @Test
    public void testVarFactory() throws Exception {
        DateVar dateVar = makeVar("D", "Date", DateVar::new);
        dateVar.setValue(new Date());
        System.out.println(dateVar);
        DateVar dateTypedVar = makeTypedVar("D", "Date", new Date(), DateVar::new);
        System.out.println(dateTypedVar);
        TypedVarFactory<Date, DateVar> dateTypedFactory = DateVar::new;
        System.out.println(dateTypedFactory.apply("D", "Date", new Date()));
        BooleanVar booleanVar = makeVar("B", "Boolean", BooleanVar::new);
        booleanVar.setValue(true);
        System.out.println(booleanVar);
        BooleanVar booleanTypedVar = makeTypedVar("B", "Boolean", true, BooleanVar::new);
        System.out.println(booleanTypedVar);
        TypedVarFactory<Boolean, BooleanVar> booleanTypedFactory = BooleanVar::new;
        System.out.println(booleanTypedFactory.apply("B", "Boolean", true));
    }
    private <V extends Var<T>, T extends Serializable> V makeVar(final String name, final String displayName,
            final VarFactory<V> varFactory) {
        V var = varFactory.apply(name, displayName);
        return var;
    }
    private <V extends Var<T>, T extends Serializable> V makeTypedVar(final String name, final String displayName, final T value,
            final TypedVarFactory<T, V> varFactory) {
        V var = varFactory.apply(name, displayName, value);
        return var;
    }
    @FunctionalInterface
    static interface VarFactory<R> {
        // Don't need type variables for name and displayName because they are always String
        R apply(String name, String displayName);
    }
    @FunctionalInterface
    static interface TypedVarFactory<T extends Serializable, R extends Var<T>> {
        R apply(String name, String displayName, T value);
    }
    static class Var<T extends Serializable> {
        private String name;
        private String displayName;
        private T value;
        public Var(final String name, final String displayName) {
            this.name = name;
            this.displayName = displayName;
        }
        public Var(final String name, final String displayName, final T value) {
            this(name, displayName);
            this.value = value;
        }
        public void setValue(final T value) {
            this.value = value;
        }
        @Override
        public String toString() {
            return String.format("%s[name=%s, displayName=%s, value=%s]", getClass().getSimpleName(), this.name, this.displayName,
                    this.value);
        }
    }
    static class DateVar extends Var<Date> {
        public DateVar(final String name, final String displayName) {
            super(name, displayName);
        }
        public DateVar(final String name, final String displayName, final Date value) {
            super(name, displayName, value);
        }
    }
    static class BooleanVar extends Var<Boolean> {
        public BooleanVar(final String name, final String displayName) {
            super(name, displayName);
        }
        public BooleanVar(final String name, final String displayName, final Boolean value) {
            super(name, displayName, value);
        }
    }
}
在寻找参数化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()。
此方法允许使用多个参数,动态字符串处理,字符串常量前缀,后缀等。
从理论上讲,使用身份还应该比String :: new略有优势,它将始终创建一个新字符串。
正如Jacob Zimmerman所指出的那样,更简单的参数化形式
Supplier<Foo> makeFooFromString(String str1, String str2) { 
    return () -> new Foo(str1, str2); 
}
永远是可能的。在上下文中这是否有意义取决于情况。
同样如上所述,静态方法引用调用需要相应方法的数量和返回/参数的类型,以匹配使用函数(流)的方法所期望的方法。
如果您有一个构造函数,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);
    }
}