Supponiamo di avere un flusso di cose e che voglio "arricchirle" a metà flusso, che posso usare peek()
per fare questo, ad esempio:
streamOfThings.peek(this::thingMutator).forEach(this::someConsumer);
Supponiamo che la mutazione delle cose a questo punto nel codice sia un comportamento corretto - ad esempio, il thingMutator
metodo può impostare il campo "lastProcessed" sull'ora corrente.
Tuttavia, peek()
nella maggior parte dei contesti significa "guardare, ma non toccare".
L'uso peek()
per mutare gli elementi del flusso è un antipattern o sconsiderato?
Modificare:
L'approccio alternativo, più convenzionale, sarebbe quello di convertire il consumatore:
private void thingMutator(Thing thing) {
thing.setLastProcessed(System.currentTimeMillis());
}
a una funzione che restituisce il parametro:
private Thing thingMutator(Thing thing) {
thing.setLastProcessed(currentTimeMillis());
return thing;
}
e usa map()
invece:
stream.map(this::thingMutator)...
Ma questo introduce il codice superficiale (il return
) e non sono convinto che sia più chiaro, perché sai peek()
restituisce lo stesso oggetto, ma con map()
un colpo d'occhio non è nemmeno chiaro che è la stessa classe di oggetti.
Inoltre, con peek()
te puoi avere una lambda che muta, ma con map()
te devi costruire un disastro ferroviario. Confrontare:
stream.peek(t -> t.setLastProcessed(currentTimeMillis())).forEach(...)
stream.map(t -> {t.setLastProcessed(currentTimeMillis()); return t;}).forEach(...)
Penso che la peek()
versione sia più chiara e che la lambda sia chiaramente mutante, quindi non c'è alcun effetto "misterioso". Allo stesso modo, se viene utilizzato un riferimento al metodo e il nome del metodo implicava chiaramente una mutazione, anche questo è chiaro e ovvio.
Su una nota personale, non esito a usare peek()
per mutare - lo trovo molto conveniente.
peek
un flusso che genera dinamicamente i suoi elementi? Funziona ancora o si perdono le modifiche? La modifica degli elementi di un flusso mi sembra inaffidabile.
List<Thing> list; things.stream().peek(list::add).forEach(...);
molto utile. Ultimamente. L'ho usato per aggiungere informazioni per la pubblicazione: Map<Thing, Long> timestamps = ...; return things.stream().peek(t -> t.setTimestamp(timestamp.get(t))).collect(toList());
. So che ci sono altri modi per fare questo esempio, ma sto semplificando eccessivamente qui. L'utilizzo peek()
produce un codice IMHO più compatto ed elegante. Leggibilità a parte, questa domanda riguarda davvero ciò che hai sollevato; è sicuro / affidabile?
peek
? Ho una domanda simile su StackOverflow e spero che tu possa guardarlo e dare il tuo feedback. Grazie. stackoverflow.com/questions/47356992/...