Reçoit une instance d'une interface fonctionnelle qui crée une instance de type T en tant qu'argument.
// newT()Méthodes qui nécessitent
<T> T doSomething(Supplier<T> supplier) {
T instance = supplier.get();
return instance;
}
//Méthode pour appeler doSomething
void caller() {
Test instance = this.doSomething(() -> new Test());
}
Même si vous savez que new T ()
est un anti-pattern en premier lieu, il y a des moments où vous voulez faire new T ()
.
Les modèles suivants sont souvent présentés comme des solutions à ce moment-là.
<T> T doSomething(Class<T> clazz) throws InstantiationException, IllegalAccessException {
T instance = clazz.newIntance();
return instance;
}
void caller() {
Test instance = this.doSomething(Test.class);
}
Le problème avec ce code est qu'il lève une exception vérifiée.
Lancez ʻInstantiationException et ʻIllegalAccessException
comme dans le code ci-dessus.
Je pense que c'est une conception raisonnable pour le côté Class.newInstance ()
, mais il y a des moments où l'utilisateur peut être sûr que le constructeur ne lèvera pas d'exception ...
Ensuite, il est difficile de se donner la peine de "essayer-attraper" ou de "lancer" l'exception ci-dessus.
De plus, puisqu'il s'agit d'une exception de vérification, elle est incompatible avec stream
[^ 1], et try-catch
est requis en interne.
<T extends SuperTest> List<T> doSomething(Class<T> clazz, List<String> valueList) throws InstantiationException, IllegalAccessException {
return valueList.stream()
.map(value -> {
//Je veux écrire intelligemment avec stream, mais essayez-catch…
try {
T obj = clazz.newInstance();
obj.setValue(value);
} catch (Exception e) {
throw new RuntimeException(e);
}
})
.collect(Collectors.toList());
}
À cet égard, l'interface fonctionnelle ne génère pas d'exceptions de vérification supplémentaires, elle est donc relativement propre (à moins qu'il n'y ait des «throws» dans le constructeur). [^ 1]: Pour être exact, il est incompatible avec l'interface fonctionnelle.
Si le constructeur prend un argument, utilisez une instance de Function <T, R>
.
S'il y en a deux, BiFunction <T, U, R>
.
S'il y en a 3 ou plus, créez une classe pour l'argument ou utilisez java.util.Map
.
1 argument
// newT()Méthodes qui nécessitent
<T> T doSomething(Function<String, T> func) {
T instance = func.apply("Arguments du constructeur");
return instance;
}
//Méthode pour appeler doSomething
void caller() {
Test instance = this.doSomething((str) -> new Test(str));
}
Deux arguments
// newT()Méthodes qui nécessitent
<T> T doSomething(BiFunction<String, Integer, T> func) {
T instance = func.apply("Arguments du constructeur", 1);
return instance;
}
//Méthode pour appeler doSomething
void caller() {
Test instance = this.doSomething((str, number) -> new Test(str, number));
}
Recommended Posts