Differenza tra peek() e forEach() Java 8

di il
7 risposte

Differenza tra peek() e forEach() Java 8

So che peek()
Stream<T> peek(Consumer<? super T> action)
è utile per il debug perché consente di eseguire un’operazione allo stream senza cambiare quest’ultimo, ma forEach()
void forEach(Consumer<? super T> action)
è utilizzato per ciclare lo stream come alternativa al for (visto che non è possibile utilizzarlo con gli stream).
Quindi fanno la stessa cosa?

7 Risposte

  • Re: Differenza tra peek() e forEach() Java 8

    marcop97 ha scritto:


    Quindi fanno la stessa cosa?
    "Nì" (sì e no). Allora: entrambi ricevono un Consumer, quindi va passata una "funzione" che RICEVE l'elemento i-esimo dello stream.
    Ma c'è una differenza fondamentale, che è ben evidente dal tipo di ritorno:
    - peek restituisce un Stream, quindi può essere messo "in mezzo" ad una catena di altre operazioni.
    - forEach ha void come tipo di ritorno, quindi è una terminal operation, ovvero può essere solamente l'ultima operazione in una catena di operazioni.
  • Re: Differenza tra peek() e forEach() Java 8

    andbin ha scritto:


    marcop97 ha scritto:


    Quindi fanno la stessa cosa?
    "Nì" (sì e no). Allora: entrambi ricevono un Consumer, quindi va passata una "funzione" che RICEVE l'elemento i-esimo dello stream.
    Ma c'è una differenza fondamentale, che è ben evidente dal tipo di ritorno:
    - peek restituisce un Stream, quindi può essere messo "in mezzo" ad una catena di altre operazioni.
    - forEach ha void come tipo di ritorno, quindi è una terminal operation, ovvero può essere solamente l'ultima operazione in una catena di operazioni.
    Ok grazie, ho capito!

    Allora, prendendo questo codice per esempio:
     
    List<String> nL = Arrays.asList("Jim", "John", "Jeff");
    Function<String, String> funVal = s -> "Hello : ".concat(s);
            nL.stream()
                    .map(funVal)
                    .peek(System.out::print);
    Come funziona adesso il peek()? Non stampa nulla finchè non metto una operazione terminale.
    Per esempio se metto .count() stampa.
  • Re: Differenza tra peek() e forEach() Java 8

    marcop97 ha scritto:


    Non stampa nulla finchè non metto una operazione terminale.
    Ma allora devi comprendere meglio gli stream!!

    Gli Stream sono "lazy", ovvero da soli non fanno nulla. Ci deve essere qualcuno che tira fuori gli elementi. Quando un metodo (es. il filter, map) restituisce un Stream (e lo restituisce subito, non elabora alcun elemento in quel momento!), questo sostanzialmente è solo una specie di "ricetta" che descrive come applicare quel concetto (es. filtraggio degli elementi).
    Ma alla fine ci DEVE essere una operazione "terminale". Questa va materialmente a consumare gli elementi dell'ultimo Stream, che li prenderà (mappati, filtrati ecc..) dal precedente Stream che ecc...

    Se non c'è una terminal operation, la catena degli Stream di fatto non serve a nulla.

    Quindi:
    - se un metodo restituisce un Stream, è una intermediate operation, "lazy"
    - se un metodo restituisce altro non Stream, è una terminal operation, che materialmente consuma gli elementi
  • Re: Differenza tra peek() e forEach() Java 8

    andbin ha scritto:


    Quindi:
    - se un metodo restituisce un Stream, è una intermediate operation, "lazy"
    - se un metodo restituisce altro non Stream, è una terminal operation, che materialmente consuma gli elementi
    Si, effettivamente è quello che dice la documentazione!
    Non c'è un metodo per controllare lo stato dello stream? Se effettivamente sta lavorando, ha terminato, ecc.
  • Re: Differenza tra peek() e forEach() Java 8

    marcop97 ha scritto:


    Non c'è un metodo per controllare lo stato dello stream? Se effettivamente sta lavorando, ha terminato, ecc.
    Quando la terminal operation ha terminato ..... ha terminato. (e anzi, c'è anche da dire che certe terminal operation possono anche non esaminare tutti gli elementi, se ne bastano di meno per ottenere il risultato)

    Quale è il dubbio?
  • Re: Differenza tra peek() e forEach() Java 8

    andbin ha scritto:


    marcop97 ha scritto:


    Non c'è un metodo per controllare lo stato dello stream? Se effettivamente sta lavorando, ha terminato, ecc.
    Quando la terminal operation ha terminato ..... ha terminato.
    Niente, tranquillo.
    Il mio dubbio era sapere se effettivamente il codice continuava durante l'esecuzione dello stream oppure no.
    Effettivamente generando uno stream infinito, se prima non finisce lo stream non va avanti:
    Stream<Integer> s = Stream.iterate(1, n -> n + 1);
            s.forEach(System.out::println);
    
            System.out.println("Stampa la fine");
    e l'output è:
    1977, 241978, 241979, 241980 ...
    senza Stampa la fine
  • Re: Differenza tra peek() e forEach() Java 8

    marcop97 ha scritto:


    Il mio dubbio era sapere se effettivamente il codice continuava durante l'esecuzione dello stream oppure no.
    La terminal operation è sincrona, ovvero come qualunque altra normale invocazione di metodo, tiene "impegnato" il thread corrente che l'ha invocato.
    Quindi è assolutamente logico/normale che la istruzione seguente non avviene fintanto che la terminal operation è in esecuzione.

    marcop97 ha scritto:


    Effettivamente generando uno stream infinito, se prima non finisce lo stream non va avanti:
    Se crei uno stream potenzialmente "infinito" (es. banalmente la generazione continua di numeri casuali) ..... beh è un altro problema.
Devi accedere o registrarti per scrivere nel forum
7 risposte