web-dev-qa-db-ja.com

Java 8コンストラクターに引数を持つサプライヤー

サプライヤが引数なしのコンストラクタのみをサポートするのはなぜですか?

デフォルトのコンストラクタが存在する場合、これを行うことができます:

create(Foo::new)

しかし、唯一のコンストラクタが文字列をとる場合、私はこれをしなければなりません:

create(() -> new Foo("hello"))
59
cahen

これはメソッド参照構文の制限にすぎません。引数を渡すことはできません。構文の仕組みです。

51
Louis Wasserman

ただし、TをとるStringの1引数コンストラクタは、Function<String,T>と互換性があります。

Function<String, Foo> fooSupplier = Foo::new;

どのコンストラクターが選択されるかは、ターゲットタイプの形状に基づいて、オーバーロード選択の問題として扱われます。

50
Brian Goetz

メソッド参照が好きな場合は、bindメソッドを自分で記述して使用できます。

public static <T, R> Supplier<R> bind(Function<T,R> fn, T val) {
    return () -> fn.apply(val);
}

create(bind(Foo::new, "hello"));
36
Tagir Valeev

サプライヤが引数なしのコンストラクタでのみ動作するのはなぜですか?

1引数コンストラクタは、Java.util.function.Function<T,R>R apply(T)など、1つの引数と1つの戻り値を持つSAMインターフェイスと同型であるためです。

一方、Supplier<T>T get()は、ゼロ引数コンストラクターと同型です。

単に互換性がありません。 create()メソッドは、さまざまな機能インターフェイスを受け入れ、指定された引数に応じて異なる動作をするためにポリモーフィックであるか、2つのシグネチャ間のグルーコードとして動作するラムダボディを記述する必要があります。

ここで満たされていない期待は何ですか?あなたの意見ではshouldはどうなりますか?

12
the8472

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 ...」呼び出しに変更する必要があります。

9
Jacob Zimmerman

サプライヤーを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);
        }
    }
}
0
Nathan Niesen