2013-01-10 23 views
10

Wiem, że istnieje kilka podobnie uprawnionych pytań tam, ale większość z nich po prostu zapomniała umieścić dyrektywę close() w swoim strumieniu. Tutaj jest inaczej.wyciek zasobów: "w" nigdy nie jest zamknięty, ale jest zamknięty

Powiedzmy mam następujący minimalny przykład:

public void test() throws IOException 
{ 
    InputStream in; 
    if(file.exists()) 
    { 
     in = new FileInputStream(file); 
    } 
    else 
    { 
     in = new URL("some url").openStream(); 
    } 
    in.close(); 
} 

To daje mi Resource leak: 'in' is never closed ostrzeżenie w Eclipse (Juno SR1). Ale kiedy przesunąć in.close() w bloku warunkowego, ostrzeżenia znika:

public void test() throws IOException 
{ 
    InputStream in; 
    if(file.exists()) 
    { 
     in = new GZIPInputStream(new FileInputStream(file)); 
     in.close(); 
    } 
    else 
    { 
     in = new URL("some URL").openStream(); 
    } 
} 

Co tu się dzieje?

+0

Ostrzeżenie, gdzie. IDE? Kompilacja Java? Które IDE? Która wersja? – Gimby

+0

* "... ostrzeżenia znikają:" *. Jakie ostrzeżenia? –

+3

Powinieneś mieć blok try/finally. Zamknij strumień w bloku finally, aby upewnić się, że nie stracisz, jeśli zostanie zgłoszony wyjątek. – duffymo

Odpowiedz

5

Oto jak ja to napisać:

public void test() throws IOException 
{ 
    InputStream in = null; 
    try { 
     if(file.exists()) { 
      in = new FileInputStream(file); 
     } else { 
      in = new URL("some url").openStream(); 
     } 
     // Do something useful with the stream. 
    } finally { 
     close(in); 
    } 
} 

public static void close(InputStream is) { 
    try { 
     if (is != null) { 
      is.close(); 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 
+1

Dzięki, to naprawdę działa. Jednak nadal nie rozumiem, jak to się dzieje, że 'in! = Null' I wyjątek jest generowany przez konstruktor' FileInputStream'. Załóżmy, że konstruktor 'FileInputStream' zgłasza wyjątek. Oznacza to, że 'in' jest nadal puste. W związku z tym instrukcja 'is.close()' jest ignorowana tak czy inaczej? – theV0ID

+1

Wolałbym przegłosować i przyjąć podziękowania. Twój przykład jest wymyślny, ponieważ nie robisz nic innego, tylko wywołujesz konstruktora. Ale jeśli faktycznie korzystałeś z InputStream, mógłbyś rzucić wyjątek, jeśli odczyt nie powiedzie się. I nic nie jest "ignorowane". Tak nie działają programy. – duffymo

+0

Począwszy od wersji Java 7, możesz po prostu użyć try z zasobami. – dramzy

4

Podejrzewam, że ostrzeżenie jest nieprawidłowe. Może to oznaczać, że zamykasz strumień w tym samym zakresie. W drugim przypadku nie zamykasz drugiego strumienia.

+1

Zgadzam się z tą odpowiedzią i przegłosowałem bezsensowne i niewyjaśnione pochopne stanowisko. Ostrzeżenie jest wyraźnie nieprawidłowe. Drugim przykładem, gdzie naprawdę * jest * brakujące zakończenie, dowodzi tego. – EJP

6

powodu wyjątku IO, można uruchomić do wycieku zasobów (poentially)

Spróbuj wykonać następujące czynności:

public void test() throws IOException 
{ 
    InputStream in= null; 
    try { 
     if(file.exists()) 
     { 
      // In this case, if the FileInputStream call does not 
      // throw a FileNotFoundException (descendant of IOException) 
      // it will create the input stream which you are wrapping 
      // in a GZIPInputStream (no IO exception on construction) 
      in = new GZIPInputStream(new FileInputStream(file)); 
     } 
     else 
     { 
      // Here however, if you are able to create the URL 
      // object, "some url" is a valid URL, when you call 
      // openStream() you have the potential of creating 
      // the input stream. new URL(String spec) will throw 
      // a MalformedURLException which is also a descendant of 
      // IOException. 
      in = new URL("some url").openStream(); 
     } 

     // Do work on the 'in' here 
    } finally { 
     if(null != in) { 
      try 
      { 
       in.close(); 
      } catch(IOException ex) { 
       // log or fail if you like 
      } 
     } 
    } 
} 

Doing powyższe będzie upewnij się, że zamknięty strumień lub w najmniej zrobili to najlepiej.

W oryginalnym kodzie zadeklarowano InputStream, ale nigdy nie zostało ono zainicjowane. Na początku jest to zła forma. Zainicjuj to na wartość null, jak pokazano powyżej. Czuję, że nie korzystam z Juno w tej chwili, jest to, że widzi, że InputStream "w" może potencjalnie przejść przez wszystkie obręcze i płotki, aby dostać się do punktu, w którym zamierzasz go użyć. Niefortunne, jak ktoś zauważył, twój kod jest trochę podejrzany na przykład. Robiąc to tak jak szczegółowo, jak również @ duffymo, pozbędziesz się ostrzeżenia.

+0

Dzięki, to działa. Mam jednak problem z rozumieniem tego rozwiązania. Tak samo jest z tą odpowiedzią tutaj: [link] (http://stackoverflow.com/a/14255849/1444073) Czy możesz to wyjaśnić? – theV0ID

0

Twój strumień wewnętrzny może nie zostać zainicjowany, jeśli plik nie istnieje i próbujesz zamknąć nieistniejący plik.

Twój drugi przykład będzie również wymagał zamknięcia oświadczenia, aby uniknąć wycieków.

+0

Nie. Jeśli "in" nie można zainicjować, zgłoszony zostanie wyjątek, a funkcja in.close() nie zostanie osiągnięta. Ten kod nie może "próbować zamknąć nieistniejącego pliku". – EJP

0

Ta sama raportowania Eclipse może się zdarzyć, gdy jawnie wyjątek po otwarciu Twojego zasobu jak:

public void method() throws IOException { 
    BufferedReader br = new BufferedReader(new FileReader("myfile.txt")); 
    while (br.ready()) { 
     String line = br.readLine(): 
     if (line.length() > 255) { 
     throw new IOException("I am some random IOException"); 
     } 
    } 
    br.close(); 
} 

To jest jakiś wymyślony kod do celów demonstracyjnych, więc nie wyglądaj zbyt mocno.

Jeśli ktoś skomentował linię, ostrzeżenie zniknie. Oczywiście zamiast tego chcesz się upewnić, że zasób jest właściwie zamknięty. Możesz zrobić:

if (line.length() > 255) { 
    br.close(); 
    throw new IOException("I am some random IOException"); 
} 

Nie należy jednak polegać na ostrzeżeniach Eclipse w tym przypadku. Przyzwyczajaj się używać podejścia try/finally, aby upewnić się, że zasoby są prawidłowo i konsekwentnie zamykane.

0

mam coś takiego:

InputStream content = httpResponse.getEntity()==null?null:httpResponse.getEntity().getContent(); 

który daje taką samą warrning. Ale jeśli zostawię to tak:

InputStream content =httpResponse.getEntity().getContent(); 

Nie otrzymuję żadnych ostrzeżeń. Czy nie jest dziwne czy co?

- Mam nadzieję, że moje informacje dodają wiedzę do pierwotnego pytania. Dzięki!

+0

i jeśli napiszę to w normalnym poleceniu JEŻELI, ponownie nie otrzymam żadnych ostrzeżeń. Hmm ... – Edwin

Powiązane problemy