サプライヤが引数なしのコンストラクタのみをサポートするのはなぜですか?
デフォルトのコンストラクタが存在する場合、これを行うことができます:
create(Foo::new)
しかし、唯一のコンストラクタが文字列をとる場合、私はこれをしなければなりません:
create(() -> new Foo("hello"))
これはメソッド参照構文の制限にすぎません。引数を渡すことはできません。構文の仕組みです。
ただし、T
をとるString
の1引数コンストラクタは、Function<String,T>
と互換性があります。
Function<String, Foo> fooSupplier = Foo::new;
どのコンストラクターが選択されるかは、ターゲットタイプの形状に基づいて、オーバーロード選択の問題として扱われます。
メソッド参照が好きな場合は、bind
メソッドを自分で記述して使用できます。
public static <T, R> Supplier<R> bind(Function<T,R> fn, T val) {
return () -> fn.apply(val);
}
create(bind(Foo::new, "hello"));
サプライヤが引数なしのコンストラクタでのみ動作するのはなぜですか?
1引数コンストラクタは、Java.util.function.Function<T,R>
のR apply(T)
など、1つの引数と1つの戻り値を持つSAMインターフェイスと同型であるためです。
一方、Supplier<T>
のT get()
は、ゼロ引数コンストラクターと同型です。
単に互換性がありません。 create()
メソッドは、さまざまな機能インターフェイスを受け入れ、指定された引数に応じて異なる動作をするためにポリモーフィックであるか、2つのシグネチャ間のグルーコードとして動作するラムダボディを記述する必要があります。
ここで満たされていない期待は何ですか?あなたの意見ではshouldはどうなりますか?
Supplier<T>
インターフェースは、() -> T
のシグニチャーを持つ関数を表します。つまり、パラメーターを取らず、タイプT
の何かを返します。引数として提供するメソッド参照は、渡されるためにその署名の後に続く必要があります。
コンストラクタで動作するSupplier<Foo>
を作成する場合は、@ Tagir Valeevが提案する一般的なバインドメソッドを使用するか、より特殊なメソッドを作成します。
常にそのSupplier<Foo>
文字列を使用する"hello"
が必要な場合は、メソッドまたはSupplier<Foo>
変数として、2つの異なる方法のいずれかで定義できます。
方法:
static Foo makeFoo() { return new Foo("hello"); }
変数:
static Supplier<Foo> makeFoo = () -> new Foo("hello");
メソッドreference(create(WhateverClassItIsOn::makeFoo);
)を使用してメソッドを渡すことができ、変数は単にcreate(WhateverClassItIsOn.makeFoo);
という名前を使用して渡すことができます。
メソッドは、メソッド参照として渡されるコンテキストの外で使用する方が簡単であるため、もう少し好ましいです。また、誰かが() -> T
または() -> Foo
特に。
引数として任意の文字列を取ることができるSupplier
を使用する場合は、Function
を指定する必要性をバイパスして、前述のバインドメソッド@Tagirのようなものを使用する必要があります。
Supplier<Foo> makeFooFromString(String str) { return () -> new Foo(str); }
これを次のような引数として渡すことができます:create(makeFooFromString("hello"));
ただし、少しだけ明確にするために、すべての「make ...」呼び出しを「supply ...」呼び出しに変更する必要があります。
サプライヤーを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);
}
}
}