Per quanto ne so, ci sono solo due tipi di funzioni, distruttive e costruttive.
Mentre la funzione costruttiva, come suggerisce il nome, costruisce qualcosa, una distruttiva distrugge qualcosa, ma non nel modo in cui potresti pensare ora.
Ad esempio, la funzione
Function<Integer,Integer> f = (x,y) -> x + y
è costruttivo . Poiché hai bisogno di costruire qualcosa. Nell'esempio hai costruito la tupla (x, y) . Le funzioni costruttive hanno il problema di non essere in grado di gestire infiniti argomenti. Ma la cosa peggiore è che non puoi lasciare una discussione aperta. Non puoi semplicemente dire "beh, lascia x: = 1" e provare ogni y che potresti voler provare. Devi costruire ogni volta l'intera tupla con
x := 1. Quindi, se ti piace vedere cosa restituiscono le funzioni, y := 1, y := 2, y := 3devi scrivere f(1,1) , f(1,2) , f(1,3).
In Java 8, le funzioni costruttive dovrebbero essere gestite (la maggior parte delle volte) utilizzando riferimenti a metodi perché non c'è molto vantaggio nell'usare una funzione lambda costruttiva. Sono un po 'come i metodi statici. Puoi usarli, ma non hanno uno stato reale.
L'altro tipo è quello distruttivo, prende qualcosa e lo smantella per quanto necessario. Ad esempio, la funzione distruttiva
Function<Integer, Function<Integer, Integer>> g = x -> (y -> x + y)
fa lo stesso della funzione fche era costruttiva. I vantaggi di una funzione distruttiva sono che ora puoi gestire infiniti argomenti, il che è particolarmente conveniente per i flussi, e puoi semplicemente lasciare gli argomenti aperti. Quindi, se vuoi di nuovo vedere come sarebbe il risultato se x := 1e y := 1 , y := 2 , y := 3, puoi dire h = g(1)ed
h(1)è il risultato per y := 1, h(2)per y := 2e h(3)per y := 3.
Quindi qui hai uno stato fisso! È abbastanza dinamico e la maggior parte delle volte è quello che vogliamo da un lambda.
I pattern come Factory sono molto più facili se puoi semplicemente inserire una funzione che fa il lavoro per te.
Quelli distruttivi si combinano facilmente tra loro. Se il tipo è giusto puoi semplicemente comporli come preferisci. Usandolo, puoi facilmente definire morfismi che rendono (con valori immutabili) i test molto più facili!
Puoi farlo anche con uno costruttivo, ma la composizione distruttiva sembra più carina e più simile a un elenco o un decoratore, e quella costruttiva assomiglia molto a un albero. E cose come il backtracking con funzioni costruttive non sono piacevoli. Puoi semplicemente salvare le funzioni parziali di una distruttiva (programmazione dinamica), e su "backtrack" basta usare la vecchia funzione distruttiva. Ciò rende il codice molto più piccolo e meglio leggibile. Con le funzioni costruttive devi più o meno ricordare tutti gli argomenti, il che può essere molto.
Allora perché c'è bisogno di BiFunctiondovrebbe essere più interrogativo che perché non ce n'è TriFunction?
Prima di tutto, molto tempo hai solo pochi valori (meno di 3) e hai bisogno solo di un risultato, quindi una normale funzione distruttiva non sarebbe affatto necessaria, una costruttiva andrebbe bene. E ci sono cose come le monadi che hanno davvero bisogno di una funzione costruttiva. Ma a parte questo, non ci sono davvero molte buone ragioni per cui esiste BiFunction. Il che non significa che debba essere rimosso! Combatto per le mie Monadi finché non muoio!
Quindi, se hai molti argomenti, che non puoi combinare in una classe contenitore logica, e se hai bisogno che la funzione sia costruttiva, usa un riferimento al metodo. Altrimenti prova a usare la nuova abilità acquisita delle funzioni distruttive, potresti trovarti a fare molte cose con molte meno righe di codice.