Dichiarazione di lambda in Java8

4

Quale sarebbe la migliore pratica per dichiarare lambda nel codice Java8? Com'è stato progettato per essere usato?

Ad esempio, supponiamo che abbiamo un metodo che accetta Function . Voglio fornire l'implementazione della funzione che può essere riusabile. Quindi posso fare questo:

[A] Implementa un'interfaccia Function :

public class Foo implements Function<A,B> {
    public B apply(A a) {...}
}
...
useFunction(new Foo());

[B] dichiara Function come lambda in un campo static :

public interface Foo {
    Function<A,B> bar = it -> { ....}
}
...
useFunction(Foo.bar);

[C] Usa riferimento al metodo:

public class Foo {
    public static B bar(A a) {...}
}
...
useFunction(Foo::bar);

Fino alla programmazione funzionale in java8, ho provato a non inquinare il codice con static s. Tuttavia, ora sono in qualche modo "obbligato" a usare la statica (o singleton globali) per archiviare i lambda riutilizzabili.

Modifica

Ho un codice che restituisce quanto segue in diversi punti:

return CompletableFuture.supplyAsync(() -> {
...
}
.exceptionally(FooExceptionWrapper::wrap);

Come vedi, voglio condividere le istanze del wrapper (che è un Function ), e ancora rimanere fluente con il codice. Ci sono molti modi in cui possiamo condividere questo.

Se creo nuove istanze ogni volta (come in A ), creeremo nuove istanze per ogni chiamata, che va bene; eppure GC verrà chiamato più frequentemente. Posso invece creare un singleton e dato che questo è un Function , la condivisione attraverso i thread non sarà un problema. Quindi potrei memorizzarlo in alcune variabili. Ora, vorrei mettere il codice di gestione fuori da questa classe (semplice per ridurre le dimensioni e la responsabilità della classe). Quindi uso l'approccio A - ma voglio ancora vedere se c'è un modo più "corretto" per questo. Non ci sono molti progetti java8 e molte persone usano i campi statici (come in B ); Sto solo mettendo in discussione tutto ciò.

    
posta igor 30.12.2014 - 16:34
fonte

3 risposte

5

Se si prevede di riutilizzare o condividere una funzione, impostarla come metodo e utilizzare un riferimento al metodo. Se hai solo bisogno di un breve pezzo di logica usa e getta, rendilo un lambda. La creazione esplicita di istanze di un'interfaccia funzionale non presenta vantaggi e presenta svantaggi:

  • Meno idiomatico
  • Ulteriori informazioni
  • Ti impegni a digitare in anticipo, mentre un riferimento al metodo o lambda corrisponderà a qualsiasi interfaccia funzionale con la firma corretta.
  • Molto probabilmente meno efficiente
risposta data 30.12.2014 - 21:09
fonte
2

Preferirei generalmente il metodo A perché è l'idioma più familiare ai programmatori Java (essendo l'unica delle opzioni disponibili prima di Java 8) e perché genera un codice byte leggermente migliore di C (che comporta un extra generato automaticamente adattatore di classe) che può risultare in un codice più efficiente.

Sceglierei il metodo C se (e solo se) alcuni aspetti del problema da risolvere lo rendessero più leggibile, ad esempio se avete una vasta famiglia di funzioni correlate tra cui scegliere che potrebbe essere sensibilmente implementata in un'unica classe.

Non userei mai l'opzione B, che mi sembra di usare lambda per il gusto di farlo.

    
risposta data 30.12.2014 - 19:17
fonte
2

Ci sono molti più modi per farlo in Java 8.

Per iniziare, se quello che vuoi fare in funzione è abbastanza semplice (ad esempio un solo liner), probabilmente un semplice lambda è la strada da percorrere.

foo( it -> it.getValue() > 10 ? "A" : "B" )

In questo approccio probabilmente non dovrai preoccuparti di quante istanze dell'oggetto lambda vengono create, il JLS rende concessioni in modo che la stessa istanza possa essere riutilizzata (a meno che non si tratti di un lambda di cattura)

Ora, se il codice è un po 'più complesso, allora potresti prendere in considerazione l'uso di riferimenti al metodo. Esistono molti tipi di riferimenti al metodo, non solo il riferimento al metodo statico che hai menzionato nel tuo esempio.

Puoi leggere Stato di Lambda per renderlo più chiaro .

Certamente anche la definizione di un campo statico in un'interfaccia per contenere l'oggetto target lambda mi sembra una pessima idea. I campi statici nelle interfacce vengono in genere utilizzati per le costanti poiché sono di default statici e finali e pertanto ho difficoltà a concepire uno scenario valido per questo.

    
risposta data 31.12.2014 - 14:31
fonte

Leggi altre domande sui tag