Empfängt eine Instanz einer Funktionsschnittstelle, die eine Instanz vom Typ T als Argument erstellt.
// newT()Methoden, die erfordern
<T> T doSomething(Supplier<T> supplier) {
T instance = supplier.get();
return instance;
}
//Methode zum Aufrufen von doSomething
void caller() {
Test instance = this.doSomething(() -> new Test());
}
Selbst wenn Sie wissen, dass "new T ()" in erster Linie ein Anti-Pattern ist, gibt es Zeiten, in denen Sie "new T ()" ausführen möchten. Die folgenden Muster werden zu diesem Zeitpunkt häufig als Lösungen dargestellt.
<T> T doSomething(Class<T> clazz) throws InstantiationException, IllegalAccessException {
T instance = clazz.newIntance();
return instance;
}
void caller() {
Test instance = this.doSomething(Test.class);
}
Das Problem mit diesem Code ist, dass er eine aktivierte Ausnahme auslöst. Throw Check Exceptions Wirf InstantiationException
und IllegalAccessException
wie im obigen Code. Ich denke, es ist ein vernünftiges Design für die Seite "Class.newInstance ()", aber es gibt Zeiten, in denen der Benutzer sicher sein kann, dass der Konstruktor keine Ausnahme auslöst ... Dann ist es mühsam, sich die Mühe zu machen, die obige Ausnahme zu versuchen oder zu werfen. Da es sich um eine Prüfausnahme handelt, ist es außerdem nicht mit "stream" [^ 1] kompatibel, und "try-catch" ist intern erforderlich.
<T extends SuperTest> List<T> doSomething(Class<T> clazz, List<String> valueList) throws InstantiationException, IllegalAccessException {
return valueList.stream()
.map(value -> {
//Ich möchte intelligent mit Stream schreiben, aber versuchen Sie es-catch…
try {
T obj = clazz.newInstance();
obj.setValue(value);
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList());
}
In dieser Hinsicht generiert die Funktionsschnittstelle keine zusätzlichen Prüfausnahmen, so dass sie relativ sauber ist (es sei denn, der Konstruktor enthält "Würfe"). [^ 1]: Um genau zu sein, ist es nicht mit der Funktionsschnittstelle kompatibel.
Wenn der Konstruktor ein Argument akzeptiert, verwenden Sie eine Instanz von Function <T, R>
.
Wenn es zwei gibt, BiFunction <T, U, R>
.
Wenn 3 oder mehr vorhanden sind, erstellen Sie eine Klasse für das Argument oder verwenden Sie "java.util.Map".
1 Argument
// newT()Methoden, die erfordern
<T> T doSomething(Function<String, T> func) {
T instance = func.apply("Konstruktorargumente");
return instance;
}
//Methode zum Aufrufen von doSomething
void caller() {
Test instance = this.doSomething((str) -> new Test(str));
}
Zwei Argumente
// newT()Methoden, die erfordern
<T> T doSomething(BiFunction<String, Integer, T> func) {
T instance = func.apply("Konstruktorargumente", 1);
return instance;
}
//Methode zum Aufrufen von doSomething
void caller() {
Test instance = this.doSomething((str, number) -> new Test(str, number));
}
Recommended Posts