2015-03-02 10 views
14

Dopo aver letto https://www.airpair.com/java/posts/spring-streams-memory-efficiency, sono tentato di trasmettere i risultati da un database, ma come ho discusso con un collega (cfr. Commento che ha aggiunto a questo articolo), è necessario ricordare di usare il costrutto try-with-resources per evitare eventuali perdite di memoria.Perché lo streaming Java close() dopo l'emissione di un'operazione terminale?

  1. Perché non l'8 libreria Java prendersi cura di chiusura corsi d'acqua per sé dopo ogni terminal operation (senza dover avvolgere l'istanza flusso in una prova-con-risorse)?
  2. Se applicabile, ci sono piani per questa funzionalità da aggiungere a Java o avrebbe senso richiederla?
+0

cosa intendi per "operazione terminale"? –

+9

Penso che stai mescolando 'java.io.InputStream' con' java.util.stream.Stream', che sono due concetti molto molto diversi –

+3

@ Zoltán no, sto davvero parlando di 'java.util.Stream' che è "AutoCloseable" e quindi idoneo per l'uso all'interno di "try-with-resources". @MartinSerrano Ho aggiunto un collegamento alla documentazione di Java riguardante i flussi in generale e le operazioni del terminale in particolare. –

risposta

19

Poiché gli stream che richiedono il rilascio esplicito di risorse sono in realtà un caso piuttosto insolito. Quindi abbiamo scelto di non sovraccaricare l'esecuzione di streaming con qualcosa che è valido solo per lo 0,01% degli usi.

Abbiamo fatto flusso Autocloseable in modo che sia possibile risorse liberazione dalla fonte, se si vuole, ma questo è dove ci siamo fermati, e per una buona ragione.

Non solo farebbe questo automaticamente a carico della maggior parte degli utenti con un lavoro extra di cui non hanno bisogno, ma ciò violerebbe anche un principio generale: colui che assegna la risorsa è responsabile della chiusura della risorsa. Quando si chiama

BufferedReader reader = ... 
reader.lines().op().op()... 

si sta aprendo la risorsa, non la libreria torrente l'uno e si dovrebbe chiuderlo. Infatti, poiché chiudere un flusso risultante dalla chiamata di un metodo di accesso su un oggetto che tiene risorse a volte chiude l'oggetto sottostante, probabilmente non vuoi che lo streaming chiuda il BufferedReader per te - potresti voler che rimanga aperto dopo il chiamata.

Se si desidera chiudere la risorsa, questo è troppo facile:

try (BufferedReader reader = ...) { 
    reader.lines().op()... 
} 

Probabilmente stai utilizzando i flussi in modo particolare, quindi probabilmente sembra "evidente" che cosa flussi dovrebbe fare - ma ci sono più casi d'uso là fuori che i tuoi. Quindi, piuttosto che ricorrere a casi d'uso specifici, ci siamo avvicinati dal principio generale: se hai aperto il flusso e lo vuoi chiuso, chiudilo da solo, ma se non lo hai aperto, non è per te che devi chiudere.

+0

Questo potrebbe essere un problema di catch-22, i flussi che richiedono un rilascio di risorse potrebbero essere rari perché la libreria corrente non supporta il loro caso. AFAIK, 'Stream' è stato introdotto principalmente per supportare la parallelizzazione, ma dal suo contratto API è chiaro che la parallelizzazione è solo una cosa che dovrebbe aiutare a fare. Sono sicuro che molti sviluppatori potrebbero desiderare di utilizzare l'API stream per altri scopi come l'utilizzo della memoria O (1), evitando gli eventi GC stop-the-world e avendo una chiara separazione di iterazioni e problemi di elaborazione (sto solo riusando La dicitura di Marko Topolnik qui). –

+1

Ora capisco meglio perché 'Stream' è attualmente in questo modo, quindi accetterò questa risposta. Ma per me come utente finale e con la mia attuale comprensione, l'implementazione di un flusso (nother?) Che si occupa di chiudere sempre le risorse sottostanti in un blocco finale appare ancora necessaria nella libreria Java. Correzione –

+2

: è stato introdotto lo stream per fornire un modo più astratto di esprimere le operazioni di aggregazione su dataset arbitrari; questo è un presupposto necessario per il parallelismo pratico, ma penso che tutti sarebbero d'accordo sul fatto che Stream sia piuttosto utile anche senza parallelismo. Il supporto per 'close()' e 'Autocloseable' rappresenta lo stretching del progetto per fornire un supporto minimo agli stream le cui fonti rappresentano risorse gestite dall'utente (al contrario della memoria, gestita dalla VM). Penso che questo sia davvero "2% vuoto" vs "98% pieno", probabilmente stai nuotando solo al 2% proprio adesso. –

0

Perché non l'8 libreria Java prendersi cura di se stessa chiusura flussi dopo ogni operazione terminale (senza dover avvolgere l'istanza flusso in una prova-con-risorse)?

Perché si può verificare un'eccezione durante o prima dell'operazione del terminale e perché non si desidera che l'operazione del terminale chiuda il flusso. Puoi usare try-with-resource se vuoi che lo stream si chiuda.

Se applicabile, ci sono piani per questa funzionalità da aggiungere a Java o avrebbe senso richiederlo?

Non avrebbe senso vedere la risposta sopra.

+0

hai un riferimento per questo? –

+0

@MartinSerrano un riferimento per cosa, esattamente? È banale aprire un flusso e causare un'eccezione prima di eseguire un'operazione terminale. – davmac

+0

per la tua risposta. questa è solo la tua opinione? sembra che la risposta @Zoltan sia più mirata. –

3

Penso che stai mescolando java.io.InputStream con java.util.stream.Stream, che sono due concetti molto molto diversi.

try-with-resources funziona su oggetti che implementano l'interfaccia Autoclosable, ad esempio InputStream s. InputStream s rappresentano una fonte astratta di dati relativi a IO.

java.util.stream.Stream<T> d'altro canto, implementa un concetto di programmazione funzionale, che rappresenta una sorta di collezione dinamica che non è necessariamente costruita staticamente, ma può piuttosto essere generata, e potenzialmente potenzialmente infinita.

Ciò che Marko Topolnik (l'autore dell'articolo collegato a) fa essenzialmente nell'articolo, suggerisce un modo per racchiudere una fonte IO in java.util.stream.Stream. Questo è un approccio abbastanza intelligente, ma gli java.util.stream.Stream s non sono generalmente destinati a questo scopo.

Poiché non sono in genere destinati all'uso con IO, non c'è motivo per cui includere chiusura dopo le operazioni del terminale.


EDIT:

Dopo aver chiarito che si aveva in realtà non mescolato i due (scusate per assumendo così), grazie a this answer, ho trovato che il vostro esempio esatto si risponde nel documentation of AutoCloseable (enfasi aggiunta da me):

e 'possibile, e di fatto comune, per una classe base per implementare AutoCloseable anche se non tutte le sue sottoclassi o istanze saranno conservare risorse rilasciabili. Per il codice che deve funzionare nella generalità completa o quando è noto che l'istanza AutoCloseable richiede il rilascio di risorse, si consiglia di utilizzare le strutture try-with-resources . Tuttavia, quando si utilizzano servizi come Stream che supportano sia moduli basati su I/O che non basati su I/O, i blocchi prova con risorse non sono necessari quando si utilizzano moduli non basati su I/O.

+0

'java.util.stream.Stream' implementa anche 'Autoclosable', e questo è esattamente ciò di cui tratta questa domanda. – davmac

+0

@davmac grazie per averlo indicato, ho modificato la mia risposta. –

Problemi correlati