IT박스

생성자에 인수가있는 Java 8 공급자

itboxs 2020. 12. 3. 07:39
반응형

생성자에 인수가있는 Java 8 공급자


공급 업체가 인수가없는 생성자 만 지원하는 이유는 무엇입니까?

기본 생성자가 있으면 다음과 같이 할 수 있습니다.

create(Foo::new)

그러나 유일한 생성자가 String을 취하는 경우 다음을 수행해야합니다.

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

이는 메소드 참조 구문의 한계 일 뿐이며 인수를 전달할 수 없습니다. 구문이 작동하는 방식입니다.


그러나 a T를 취하는 1-arg 생성자 String는 다음과 호환됩니다 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>'s 와 같은 1 개의 인수와 1 개의 반환 값이있는 SAM 인터페이스와 동형이기 때문 R apply(T)입니다.

반면 Supplier<T>s T get()는 인수가없는 생성자와 동형입니다.

그들은 단순히 호환되지 않습니다. 어느 당신의 create()방법에 필요한 다양한 기능의 인터페이스를 수용하고있는 인수가 제공됩니다 또는 두 개의 서명 사이의 글루 코드 역할을 할 람다 몸을 쓸 필요가 따라 다르게 행동 할 다형성 수 있습니다.

여기에서 충족되지 않은 기대는 무엇입니까? 당신의 의견으로 어떤 일어나야합니까?


Supplier<T>인터페이스의 서명 기능을 나타내는 () -> T이 매개 변수를 사용하지 않는 및 유형의 무언가를 반환 의미 T. 인수로 제공하는 메서드 참조는 전달 되려면 해당 서명을 따라야합니다.

당신은 만들려면 Supplier<Foo>@Tagir Valeev 보낸 사람이 시사하는 생성자와 작품, 당신이 사용할 수있는 일반 바인드 방법을, 또는 당신은보다 전문적인 일을합니다.

Supplier<Foo>항상 해당 "hello"문자열을 사용 하는를 원하면 메서드 또는 Supplier<Foo>변수 의 두 가지 방법 중 하나로 정의 할 수 있습니다.

방법:

static Foo makeFoo() { return new Foo("hello"); }

변하기 쉬운:

static Supplier<Foo> makeFoo = () -> new Foo("hello");

reference ( create(WhateverClassItIsOn::makeFoo);) 메서드를 사용하여 메서드를 전달할 수 있으며 변수는 단순히 이름을 사용하여 전달할 수 있습니다 create(WhateverClassItIsOn.makeFoo);.

사람도 자신의 전문 기능 인터페이스를 요구하는이 방법을 참조로 전달되는 컨텍스트 외부에서 사용하기 쉽기 때문에이 방법은 좀 더 바람직하고, 또한 인스턴스에서 사용 할 수있어 () -> T이거나 () -> Foo특별히을 .

당신이 사용하려는 경우 Supplier인수로 문자열을 취할 수를, 당신은 공급의 필요성을 우회, @Tagir 언급 바인드 방법 같은 것을 사용해야합니다 Function:

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);
        }
    }
}

참고 URL : https://stackoverflow.com/questions/31251629/java-8-supplier-with-arguments-in-the-constructor

반응형