La risposta è, come sempre, "dipende". Dipende da quanto sarà grande la collezione restituita. Dipende se il risultato cambia nel tempo e dall'importanza della coerenza del risultato restituito. E dipende molto da come è probabile che l'utente usi la risposta.
Innanzitutto, tieni presente che puoi sempre ottenere una raccolta da uno stream e viceversa:
// If API returns Collection, convert with stream()
getFoo().stream()...
// If API returns Stream, use collect()
Collection<T> c = getFooStream().collect(toList());
Quindi la domanda è, che è più utile per i tuoi chiamanti.
Se il tuo risultato potrebbe essere infinito, c'è solo una scelta: Stream.
Se il tuo risultato potrebbe essere molto grande, probabilmente preferisci Stream, dal momento che potrebbe non esserci alcun valore nel materializzarlo tutto in una volta, e ciò potrebbe creare una pressione di heap significativa.
Se tutto ciò che il chiamante sta per fare è scorrere attraverso di esso (ricerca, filtro, aggregazione), dovresti preferire Stream, poiché Stream ha già questi built-in e non è necessario materializzare una raccolta (soprattutto se l'utente potrebbe non elaborare il risultato complessivo.) Questo è un caso molto comune.
Anche se sai che l'utente lo ripeterà più volte o lo manterrà in altro modo, potresti comunque voler restituire uno Stream, per il semplice fatto che qualunque raccolta tu scelga di inserirlo (ad esempio, ArrayList) potrebbe non essere il modulo che vogliono, quindi il chiamante deve copiarlo comunque. se restituisci un flusso, possono farlo collect(toCollection(factory))
e ottenerlo esattamente nella forma che desiderano.
I suddetti casi "preferisci Stream" derivano principalmente dal fatto che Stream è più flessibile; puoi legarti in ritardo a come lo usi senza incorrere in costi e vincoli per materializzarlo in una Collezione.
L'unico caso in cui è necessario restituire una raccolta è quando vi sono forti requisiti di coerenza e si deve produrre un'istantanea coerente di un bersaglio in movimento. Quindi, vorrai inserire gli elementi in una raccolta che non cambierà.
Quindi direi che la maggior parte delle volte Stream è la risposta giusta: è più flessibile, non impone costi di materializzazione solitamente non necessari e, se necessario, può essere facilmente trasformato nella Collezione di tua scelta. A volte, tuttavia, potrebbe essere necessario restituire una raccolta (ad esempio, a causa di requisiti di coerenza elevati) oppure è possibile restituire la raccolta perché si sa come l'utente la utilizzerà e si sa che questa è la cosa più conveniente per loro.
players.stream()
è proprio un tale metodo che restituisce un flusso al chiamante. La vera domanda è: vuoi davvero vincolare il chiamante al singolo attraversamento e negargli anche l'accesso alla tua raccolta tramite l'Collection
API? Forse il chiamante vuole semplicementeaddAll
farlo in un'altra raccolta?