2010-03-22 8 views
5

È buona norma impostare i riferimenti del flusso su null dopo averli chiusi? Questo libererebbe risorse in qualche modo?Java: creazione di un riferimento null dopo la chiusura del flusso

Esempio:

BufferedReader input= new BufferedReader(new FileReader("myfile.txt")); 

// code 

input.close(); 
input = null; 

// possible more code 
+0

@Hei: Benvenuti in SO. Solo per il futuro (e se modifichi questa domanda), puoi indentare righe di codice con quattro spazi e verranno visualizzati in blocchi di codice speciali, che li rende più facili da leggere. – Pops

+0

Grazie per il commento, esaminerò quello per le domande future. – Hei

risposta

6

No, è cattiva pratica. IMO, dovresti prendere in considerazione la possibilità di creare la variabile final.

La gestione delle risorse deve essere gestita nel modo standard acquire(); try { use(); } finally { release(); }. In questo caso:

In realtà questo codice preleva qualsiasi codifica di carattere impostata come predefinita. Suggerisco di essere esplicito con un particolare set di caratteri hard-coded o Parameterise from Above.

final InputStream rawIn = new FileInputStream("myfile.txt"); 
try { 
    BufferedReader in = new BufferedReader(
     new InputStreamReader(rawIn, "UTF-8") 
    ); 

    // code 

} finally { 
    rawIn.close(); 
} 

Non si deve creare l'involucro torrenti/lettori al di fuori del blocco try (e prima che l'assegnazione delle risorse) perché potrebbero gettare. Allo stesso modo la loro chiusura potrebbe gettare (questo era in realtà un bug in BufferedOutputStream che potrebbe gettare su flush). Alcuni flussi di input possono avere altre risorse, quindi sono necessari due try { ... finally { x.close(); } s.

Per l'output, in genere è necessario flush nel normale corso degli eventi. Ma generalmente non in casi eccezionali. Infatti lodi solito fa un flush, quindi non dovresti chiuderli nel caso eccezionale. Se i decoratori sono entrambi flush e hanno risorse, allora dovrai sogghignare e scoprirlo.

Ci sono occasioni molto infrequenti quando azzerare è una buona idea. Ad esempio, se una variabile è l'unico riferimento a un oggetto di grandi dimensioni e si intende creare un nuovo oggetto di grandi dimensioni da assegnare ad esso, è preferibile cancellare il riferimento per consentire il recupero del vecchio prima di allocare il nuovo.

+5

+1 per l'uso di 'final' nella dichiarazione dello stream. -1 per la chiusura del flusso interno ('rawIn'). Devi sempre chiudere il flusso più derivato. Ad esempio nel tuo caso 'BufferedReader' potrebbe avere alcuni dati nel suo buffer interno. Chiamare chiudi in "in" scaricherà correttamente questi dati. Chiamare close su 'rawIn' lo scarterà. –

+0

Grazie per la risposta e per menzionare un caso in cui l'annullamento sarebbe una buona idea. – Hei

+0

@Alexander Pogrebnyak No. Aggiungerò una modifica. –

5

Non necessario. Basta input.close(). Ricorda che è sempre consigliabile farlo all'interno di un blocco finally. E prima di chiamare close() è meglio fare un controllo nulla come questo

finally{ 
    if(input!=null){ 
    input.close(); 
    } 
} 
+3

Se si esegue l'assegnazione originale * prima * del blocco try, non è necessario il controllo di nullità. Fallirà solo se il file non può essere aperto, nel qual caso comunque non ci sono problemi. –

1

A meno che non si sta gestendo manualmente un pool di rosources (gestire la propria memoria), non è necessario a null il flusso di input. Idealmente, qualunque funzione tu stia inserendo è piccola, e i riferimenti all'oggetto moriranno non appena l'oggetto uscirà dal campo di applicazione, contrassegnandolo comunque per la garbage collection.

Ho menzionato le risorse di pool, come se chiudeste in modo ingenuo il flusso senza annullare l'oggetto, potreste accidentalmente mantenere un riferimento dell'oggetto che non è effettivamente necessario.

3

Può rendere l'oggetto Stream in sé per la garbage collection, ma

  1. Nella maggior parte dei casi sarà passare fuori del campo di applicazione subito dopo comunque
  2. la quantità di memoria così "liberato" è del tutto insignificante
+0

Bene, non immediatamente. Dovrà passare attraverso la finalizzazione prima che la memoria venga rilasciata in una raccolta successiva. –

0

In questo caso non è necessario, il garbage collector lo raccoglierà.

Ma non è sempre una cattiva pratica assegnare null. Leggi l'articolo 6 da Effective Java, chapter 2

1

No, non lo è. Lo close() libera già la risorsa. La prassi normale è il seguente:

Resource resource = null; 
try { 
    resource = new Resource(); 
    // ... 
} finally { 
    if (resource != null) try { resource.close(); } catch (ResourceException logOrIgnore) {} 
} 

Dove Resource può essere qualsiasi risorsa esterna che si desidera utilizzare, come ad esempio InputStream, OutputStream, Reader e Writer di Java IO API, ma anche per esempio Connection, Statement e ResultSet dell'API JDBC.

La memoria non è un problema in un codice ben progettato. Se il codice lascia il blocco del metodo, è già idoneo per GC.

È possibile refactoring del close() a un metodo di utilità come:

public static void close(Closeable resource) { 
    if (resource != null) { 
     try { 
      resource.close(); 
     } catch (ResourceException logOrIgnore) { 
      // Log it? 
     } 
    } 
} 

che si può usare nel modo seguente:

} finally { 
    close(resource); 
} 

Il Apache Commons fornisce diversi metodi di utilità del genere.

+0

Oppure puoi mettere l'acquisizione della risorsa nella posizione corretta w.r.t. il 'try'. –

+0

Punto giusto, ma a volte ti piacerebbe catturare, registrare e/o rilanciare l'eccezione nello stesso blocco 'try', se necessario come un altro tipo di eccezione. – BalusC

+1

Spinga la barca fuori! Usa due blocchi 'try' !!! E poi usa l'idioma di Execute Around. –

Problemi correlati