Molte Java API hanno metodi che ritornano un Collection (eviterò di scrivere una Collection). Dalla versione 8 di Java è possibile restituire anche uno Stream. Dato che uno Stream è più flessibile ed efficiente in moti casi, le API che andremo a sviluppare dovrebbero restituire uno Stream o un Collection?
Un esempio significativo
Per restituire un Collection, gli elementi della collezione devono essere prima di tutto creati e poi caricati in memoria. Così ci sono due costi: computazionale e allocazione di memoria.
Consideriamo i seguenti due metodi dalla classe java.nio.file.Files:
static List readAllLines(Path path)
static Stream lines(Path path)
Per restituire una lista di stringhe, il metodo readAllLines() deve prima leggereil file fino alla fine e poi salvare l’intero contenuto in memoria. D’altra parte, il metodo lines() restituisce immediatamente le righe lette appena inizia a leggere il file. I costi computazionali e di allocazione di memoria sono irrisori proprio grazie al vantaggio del comportamento lazy degli Stream in Java.
Per esempio, se è necessario cercare una qualsiasi occorrenzam il programma non deve leggere fino alla fine del file, ma solo fino alla prima occorrenza:
boolean result = Files.lines(path).anyMatch(x -> x.charAt(0) == 'z');
Perché uno Stream dovrebbe essere preferito nella maggior parte dei casi?
Le ragioni per cui è altamente consigliato restituire uno Stream nella maggior parte dei casi, risiedono in queste ragioni:
- se il risultato potrebbe essere infinito, andrebbe usato uno Stream.
- Se il risultato potrebbe essere molto grande, andrebbe usato uno Stream perché un Collection avrebbe un impatto maggiore sulle richieste di Heap Memory.
- Se il chiamante necessità soltanto di iterare la collezione (search, filter, aggregate), si dovrebbe usare uno Stream perché ha già tutti questi metodi implementati e inoltre perché non è necessario caricare tutta la collezione in memoria.
- Il Collection che hai scelto per mantenere i dati non è nella forma richiesta dal chiamante. Tornando uno Stream, il chiamante ha modo di richiamare a suo piacimento docollect(toCollection(factory)).
- Se sono necessari computazioni parallele (vedi parallelStream())
Questo articolo è tratto da alcune risposte su Stack Overflow ad un post di FredOverflow .