생성자에 인수가있는 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
'IT박스' 카테고리의 다른 글
Apache 오류 : _default_ 가상 호스트가 포트 443에서 겹칩니다. (0) | 2020.12.03 |
---|---|
Android Studio의 파일에서 방법을 검색하는 방법 (0) | 2020.12.03 |
Webpack Watch가 Windows의 Webstorm에서 작동하지 않습니까? (0) | 2020.12.03 |
ID 열이있는 SqlBulkCopy 삽입 (0) | 2020.12.02 |
Android In App Billing : 애플리케이션 공개 키 보안 (0) | 2020.12.02 |