2015-06-26 13 views
12

ho una domanda per quanto riguarda Java 8. Ecco il mio codice sorgente:Applicare JDK 8 consumatori su String

final Consumer<String> d = e -> System.out.println(e); 
final Function<String, String> upper = x -> x.toUpperCase(); 
final Function<String, String> lower = x -> x.toLowerCase(); 

new Thread(() -> d.accept(upper.apply("hello 1"))).run(); 
new Thread(() -> d.accept(lower.apply("hello 2"))).run(); 

Questo funziona abbastanza bene e produce output seguente:

HELLO 1 
hello 2 

La mia domanda è ora se la sintassi sopra d.accept e upper.apply è l'unica possibile o se c'è ancora un po 'di stile "java 8 lambda" potremmo scrivere le ultime due righe.

+1

Questi lambda sono tutti candidati ideali per l'utilizzo di _method references_ invece: System.out :: println, String :: toUpperCase. –

risposta

9

Prima di dire nulla circa le espressioni lambda o interfacce funzionali, dobbiamo parlare del tuo errore davvero problematico: chiamirun()su una discussione! Se si desidera iniziare una nuova discussione, è necessario chiamare start() sull'istanza Thread, se si desidera eseguire il codice in modo sequenziale, non creare uno Thread (ma solo uno Runnable).

Detto questo, vi sono alcuni metodi default sulle interfacce funzionali di Java 8 per la combinazione di funzioni, ad es. puoi concatenare due Function s tramite Function.andThen(…) ma le combinazioni disponibili sono lontane dall'essere complete.

Se un certo compito che unisce ripete nella vostra applicazione, si può prendere in considerazione la creazione di metodi di utilità:

public static <T> Runnable bind(T value, Consumer<T> c) { 
    return()->c.accept(value); 
} 
public static <T,U> Consumer<U> compose(Function<U,T> f, Consumer<? super T> c) { 
    return u->c.accept(f.apply(u)); 
} 

new Thread(bind("Hello 1", compose(upper, d))).start(); 
new Thread(bind("Hello 2", compose(lower, d))).start(); 

Ma queste tre parti sembrano più come un compito per l'API flusso:

Stream.of("Hello 1").map(upper).forEach(d); 
Stream.of("Hello 2").map(lower).forEach(d); 

Ho lasciato la creazione del nuovo thread qui, poiché non ha qualsiasi beneficio comunque.

Se si vuole veramente l'elaborazione parallela, è possibile farlo su una base per-carattere:

"Hello 1".chars().parallel() 
    .map(Character::toUpperCase).forEachOrdered(c->System.out.print((char)c)); 

ma ancora non sarà in alcun beneficio data la semplicità del compito e l'overhead fisso del elaborazione parallela.

+1

Per quanto riguarda l'elaborazione parallela: l'implementazione predefinita di 'chars()' in JDK8 è davvero pessima. Difficilmente si otterrà la notevole accelerazione anche per le corde lunghe. È molto meglio in JDK9. –

+2

@Tagir Valeev: lo so, ma non volevo approfondire i dettagli.Dopo tutto, anche con il migliore supporto per la divisione di Java 9, il compito di questa domanda non trarrà vantaggio dall'esecuzione parallela. Dubito che ci possa mai essere un 'String' abbastanza lungo da consentire una semplice trasformazione' toUpperCase' dall'esecuzione parallela. A proposito, l'API Java 8 ha un modo per superare questa limitazione: usa 'CharBuffer.wrap (string) .chars()' invece di 'string.chars()' ... – Holger

+0

Grazie mille. Questo mi ha aiutato molto. Sei assolutamente perfetto con Thread.run. Questo era solo un esempio e non ha notato che fare con i lambda. –

3

Sì, è l'unica sintassi possibile. In realtà quando usi il lambda non sai nemmeno se è in realtà lambda o semplicemente una semplice vecchia implementazione dell'interfaccia data (tramite classe anonima o classe normale). Quindi devi usare l'interfaccia funzionale come qualsiasi altra interfaccia Java: chiama il suo metodo in modo esplicito.

4

È possibile anche scrivere in questo modo:

new Thread(() -> Stream.of("hello 1").map(upper).forEach(d)).run(); 
    new Thread(() -> Stream.of("hello 1").map(lower).forEach(d)).run(); 

O più directlry:

new Thread(() -> Stream.of("hello 1").map(String::toUpperCase).forEach(System.out::println)).run(); 
    new Thread(() -> Stream.of("hello 1").map(String::toLowerCase).forEach(System.out::println)).run(); 
Problemi correlati