È una cosa ragionevole restituire stream ovunque dovremmo normalmente restituire le raccolte?


19

Mentre sviluppo la mia API che non è legata ad alcun codice legacy, mi trovo spesso a scrivere metodi che sono puramente flussi di pipeline terminati raccogliendo i risultati. Come questo:

ImmutableSet<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfThing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey)
        .collect(MyCustomCollectors.toImmutableSet());
}

Ora, la maggior parte dei client di questa classe di solito avrà bisogno della Collection (in questo caso, un ImmutableSet) per cercare elementi e iterare su di esso, ma alcuni client potrebbero trarre vantaggio dall'avere uno Stream in modo da poter eseguire il pipe di alcune operazioni in più Streaming senza la necessità di ottenere un nuovo stream dalla raccolta. Quindi la restituzione di uno Stream offre ai clienti un superset di opzioni che avrebbero se avessero la Collezione (dopo tutto, possono sempre collect()lo Stream stesso:

Stream<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfthing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey);
        // No collect
}

Questo approccio mi sta tentando di provare perché non vedo alcun potenziale difetto che potrebbe avere. Tuttavia, non ho mai visto questo approccio in nessuna libreria (probabilmente perché non c'erano molte librerie rilasciate dopo l'apparizione di Java 8), quindi ho un po 'paura di adottarlo. Le classi di biblioteche esistenti di solito restituiscono Raccolte quando derivano qualcosa dallo stato privato.

C'è qualcosa di brutto che potrebbe accadere se decido di restituire uno Stream ovunque il mio io pre-Java-8 restituisca una Collezione? O probabilmente sto facendo qualcosa di antipatico qui con tutto ciò che deriva dallo stato privato?

Risposte:


14

Se myPrivateThingiesè modificabile, hai creato una dipendenza nascosta tra il tuo stato privato e i risultati del flusso. Se è possibile che il client induca indirettamente myPrivateThingiesa cambiare stato, otterrà un risultato diverso durante la chiamata collectrispetto a quello originariamente previsto.

Se myPrivateThingiesè immutabile, il risultato sarà referenzialmente trasparente, ma c'è un altro problema a cui bisogna fare attenzione: immondizia semantica , vale a dire trattenere grandi quantità di memoria che non sono più necessarie. Supponiamo che myPrivateThingiessia molto grande e il risultato della raccolta del flusso sia piccolo. Il client può trattenere lo stream per molto tempo dopo aver gettato via tutti i riferimenti all'oggetto che lo ha prodotto, ma ciò streamcontinua a non myPrivateThingiesdiventare spazzatura. La raccolta accanita dei risultati consentirebbe myPrivateThingiesdi essere liberato.

Questo in realtà è accaduto prima di Java 7 durante la chiamata substring. Oracle ha deciso che i potenziali risparmi in termini di efficienza derivanti dalla mancata copia della sottostringa ogni volta non valgono la pena di sorprendere l'utente medio con un consumo eccessivo di memoria. Questo non vuol dire che non c'erano casi d'uso reali per il vecchio comportamento (ad es. Parser) ma spesso raccogliere i risultati con entusiasmo è abbastanza veloce, e quando ciò accade non hai pro e un potenziale contro.

D'altro canto, la restituzione di un flusso offre al cliente la possibilità di scegliere quale struttura di dati desidera utilizzare per conservare i risultati, anziché scegliere uno per lui. Potrebbe valere la pena offrire entrambe le opzioni.


4

La cosa più importante da considerare: le Streams possono essere ripetute una sola volta, mentre si ha una maggiore flessibilità rispetto a una Collection: è possibile continuare a creare più Streams o addirittura Iteratorfare ulteriori elaborazioni ripetitive sui risultati.

Quindi, se non si è sicuri se i chiamanti del metodo useranno i risultati una volta e una sola volta, è meglio restituire a Collection.


Il tuo codice di esempio ha un errore evidente: perché dovrebbe SocialStatusavere il concetto di persona he?


3

Dal mio punto di vista, no. Le cose che puoi fare con i flussi sono un superset rigoroso di ciò che puoi fare con le raccolte e spesso possono essere rese più efficienti, quindi non c'è motivo di non usarle se non la familiarità. "Le espressioni lambda sono la droga gateway per Java 8, ma i flussi sono la vera dipendenza." (Venkat Subramaniam, Programmazione funzionale in Java )

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.