Che cosa si vuole fare è chiamata “applicazione funzione parziale” nel mondo della programmazione di funzioni o semplicemente "legare un valore a un parametro" in termini meno funzionali. Non c'è alcun metodo incorporato per questo, ma è facile da scrivere il proprio:
public static <T,U,R> Function<U,R> bind(BiFunction<T,U,R> f, T t) {
return u -> f.apply(t, u);
}
Quindi è possibile utilizzare nel vostro caso:
FooBar<X,Y> instance=…;
BiFunction<FooBar<X,Y>,X,Y> barFunction=FooBar::bar;
Function<X,Y> myBarFunction=bind(barFunction, instance);
o semplicemente
// equivalent to myBarFunction=instance::bar
Function<X,Y> myBarFunction=bind(FooBar::bar, instance);
Nota che il metodo di utilità è limitato alle interfacce funzionali che si stanno utilizzando, ad esempio Function
e BiFunction
, non ai riferimenti al metodo. Funziona con qualsiasi BiFunction
, sia implementato come riferimento al metodo, espressione lambda o classe ordinaria. Ma sarà utile solo se hai specificamente bisogno di un'istanza Function
, non di un'interfaccia funzionale arbitraria che prenda un parametro. È possibile convertire un Function
in un altro tipo di funzione a singolo argomento utilizzando ::apply
ma l'utilizzo di bind(bifunc, value)::apply
non offre alcun vantaggio rispetto a x -> bifunc.apply(value, u)
nel luogo in cui è richiesta l'istanza.
Quindi se si deve convertire BiFunction
s a Function
s vincolando un primo argomento molto spesso, il metodo di utilità potrebbe essere utile. Altrimenti, basta usare un'espressione lambda nel contesto in cui è presente il tipo di target effettivo. Naturalmente, è possibile scrivere un metodo simile anche per altre interfacce, ma questo sarà di nuovo utile solo se ne hai bisogno per quella specifica interfaccia spesso.
Per quanto riguarda le funzioni che richiedono più parametri, poiché l'API Java non fornisce tali interfacce funzionali, sarà necessario definire autonomamente l'interfaccia appropriata, che offre la possibilità di fornire la funzione di collegamento direttamente nell'interfaccia come metodi default
, ad es.
interface MyFunc3<A,B,C,R> {
R apply(A a, B b, C c);
default BiFunction<B,C,R> bind(A a) {
return (b, c) -> apply(a, b, c);
}
}
interface MyFunc4<A,B,C,D,R> {
R apply(A a, B b, C c, D d);
default MyFunc3<B,C,D,R> bind(A a) {
return (b, c, d) -> apply(a, b, c, d);
}
}
poi, se si dispone di una funzione come
MyFunc4<U, W, X, Y, Z> func = …;
si può fare qualcosa di simile
MyFunc3<W, X, Y, Z> f3 = func.bind(u);
o
BiFunction<X, Y, Z> f2 = func.bind(u).bind(w);
Brillante spiegazione come al solito, Holger. Non avevo considerato semplicemente l'aggiunta di un metodo predefinito per associare un'istanza a un'interfaccia funzionale, ma è un trucco davvero utile. –