2010-03-22 10 views
5

Czy po zamknięciu warto ustawić odwołania do strumienia na wartość null? Czy to wydanie będzie w jakikolwiek sposób dostępne?Java: tworzenie wartości odniesienia o wartości null po zamknięciu strumienia

Przykład:

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

// code 

input.close(); 
input = null; 

// possible more code 
+0

@Hei: Witamy w SO. Tylko na przyszłość (i jeśli edytujesz to pytanie), możesz wciskać linie kodu z czterema spacjami, które pojawią się w specjalnych blokach kodu, co ułatwia ich czytanie. – Pops

+0

Dziękuję za komentarz, który zajrzę w to na przyszłe pytania. – Hei

Odpowiedz

6

Nie, to jest złą praktyką. IMO, powinieneś rozważyć zrobienie zmiennej final.

Obsługa zasobów powinna być obsługiwana w standardowy sposób: acquire(); try { use(); } finally { release(); }. W takim przypadku:

final Reader rawIn = new FileReader("myfile.txt"); // Character encoding?? 
try { 
    BufferedReader in = new BufferedReader(rawIn); 

    // code 

} finally { 
    rawIn.close(); 
} 

W rzeczywistości ten kod odbiera wszelkie kodowanie znaków ustawione domyślnie. Sugeruję bycie wyraźnym z konkretnym zakodowanym na stałe zestawem znaków lub Parameterise from Above.

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

    // code 

} finally { 
    rawIn.close(); 
} 

Nie należy tworzyć owinięcia strumienie/czytelników spoza bloku try (a przed przypisaniem zasobów), ponieważ mogą one rzucać. Podobnie ich zamknięcie może rzucić (to był rzeczywiście błąd w BufferedOutputStream, który może rzucić na flush). Niektóre strumienie wejściowe mogą mieć inne zasoby, więc potrzebujesz dwóch s. try { ... finally { x.close(); }.

W przypadku danych wyjściowych generalnie należy wykonać flush w normalnym toku zdarzeń. Ale generalnie nie w wyjątkowych przypadkach. Rzeczywiście close zwykle ma wartość flush, dlatego nie należy ich zamykać w wyjątkowych przypadkach. Jeśli dekoratorzy, zarówno flush i mają zasoby, będziesz musiał uśmiechać się i go nosić.

Istnieje wiele rzadkich okazji, kiedy zerowanie jest dobrym pomysłem. Na przykład, jeśli zmienna jest jedynym odniesieniem do dużego obiektu i zamierzasz utworzyć nowy duży obiekt do przypisania do niego, najlepiej jest wyczyścić odniesienie, aby umożliwić odzyskanie starego przed przydzieleniem nowego.

+5

+1 za użycie deklaracji "final" w strumieniu. -1 dla zamykania strumienia wewnętrznego ('rawIn'). Zawsze powinieneś zamykać najbardziej uzyskany strumień. Na przykład w twoim przypadku 'BufferedReader' może mieć trochę danych w swoim wewnętrznym buforze. Wywołanie close na 'in' spowoduje prawidłowe przepłukanie tych danych. Wywołanie zamknięcia na 'rawIn' spowoduje odrzucenie go. –

+0

Dziękuję za odpowiedź i wspomnę o przypadku, w którym anulowanie byłoby dobrym pomysłem. – Hei

+0

@Alexander Pogrebnyak Nie. Dodam edycję. –

5

Niepotrzebne. Wystarczy input.close(). Pamiętaj, że zawsze warto to zrobić w bloku finally. I przed wywołaniem close() jej lepiej zrobić null czek jak ten

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

Jeśli wykonujesz oryginalne przypisanie * przed * blokiem try, nie musisz sprawdzać nieważność. Wystąpi ona tylko w przypadku, gdy nie można otworzyć pliku, w takim przypadku i tak nie ma problemu. –

1

ile jesteś ręcznego zarządzania pulę rosources (obsługa własnej pamięci), nie jest to konieczne null strumień wejściowy. Idealnie, jakakolwiek funkcja, w której się znajdujesz, jest mała, a odniesienia do obiektu umrą, gdy obiekt wykracza poza zakres, co oznacza, że ​​i tak będzie to oznaczało wyrzucanie śmieci.

Wspominam o pulowaniu zasobów, tak jakbyś naiwnie zamykał strumień bez zerowania obiektu, możesz przypadkowo przytrzymać referencję obiektu, którego faktycznie nie potrzebujesz.

3

Może to uczynić obiekt Stream sobie prawo do zbierania śmieci, ale

  1. W większości przypadków będzie to przejdzie z zakresu tuż potem i tak
  2. ilość pamięci w ten sposób „zwolniony” jest zupełnie nieistotny
+0

Cóż, nie od razu. Będzie musiała przejść przez finalizację, zanim pamięć zostanie wydana w kolejnym zbiorze. –

0

W tym przypadku nie jest to konieczne, garbage collector go zbierze.

Jednak przypisywanie null nie zawsze jest złą praktyką. Przeczytaj pozycję 6 z Effective Java, chapter 2

1

Nie, nie jest. Model close() już zwalnia zasoby. Normalną praktyką jest następujący:

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

Gdzie Resource może być żadnego zewnętrznego zasobu, który chcesz użyć, takich jak InputStream, OutputStream, Reader i Writer Java IO API, ale także na przykład Connection, Statement i ResultSet interfejsu JDBC API.

Pamięć nie jest problemem w dobrze zaprojektowanym kodzie. Jeśli kod opuści blok metod, kwalifikuje się on już do GC.

Można zreorganizujesz close() do metody Narzędzie jak:

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

, które można wykorzystać w następujący sposób:

} finally { 
    close(resource); 
} 

Apache Commons udostępnia kilka metod Narzędzie jak to.

+0

Lub możesz umieścić pozyskiwanie zasobów we właściwym miejscu w.r.t. "try". –

+0

Fajny punkt, ale czasami chciałbyś złapać, zalogować i/lub ponownie rzucić wyjątek w tym samym bloku 'try', jeśli to konieczne, jako inny rodzaj wyjątku. – BalusC

+1

Wypchnij łódź! Użyj dwóch bloków "try" !!! A następnie użyj języka Execute Around. –

Powiązane problemy