Wyciek zasobów: „w” nigdy nie jest zamykane


84

Dlaczego Eclipse wyświetla ocieplający się komunikat „Wyciek zasobów:„ in ”nigdy nie jest zamknięty” w poniższym kodzie?

public void readShapeData() {
        Scanner in = new Scanner(System.in);
        System.out.println("Enter the width of the Rectangle: ");
        width = in.nextDouble();
        System.out.println("Enter the height of the Rectangle: ");
        height = in.nextDouble();

Odpowiedzi:


69

Ponieważ nie zamykasz skanera

in.close();

39
Spowoduje to zamknięcie Scanneri wyciszenie ostrzeżenia, ale również zostanie zamknięte, System.inco zwykle nie jest pożądane.
Stuart Cook

@StuartCook +1. Coś, na co trzeba mieć oko.
informatik01

7
Dlaczego musimy zamknąć Scanner? Co oznacza „wyciek zasobów”?
Erran Morad

1
@nogard: Ta odpowiedź jest bardzo pomocny .. ale gdy używam in.close (); .. znowu pokazuje w nie mogą być rozwiązane .. Mam kod bez wyjątku .. Dzięki magazynowe
szt

3
@StuartCook, zapomniałeś wspomnieć, dlaczego zamknięcie System.injest zazwyczaj niepożądane. To dlatego, że nie będziesz w stanie ponownie z niego przeczytać. I. e. otrzymasz, java.util.NoSuchElementException: No line foundjeśli spróbujesz zadzwonić (new Scanner(System.in)).nextLine()na przykład.
Petr Bodnár

55

Jak powiedzieli inni, na zajęciach IO musisz wywołać „zamknij”. Dodam, że to świetne miejsce na skorzystanie z try - na koniec blokuj bez haczyka, tak:

public void readShapeData() throws IOException {
    Scanner in = new Scanner(System.in);
    try {
        System.out.println("Enter the width of the Rectangle: ");
        width = in.nextDouble();
        System.out.println("Enter the height of the Rectangle: ");
        height = in.nextDouble();
    } finally {
        in.close();
    }
}

Zapewnia to, że skaner jest zawsze zamknięty, co gwarantuje prawidłowe czyszczenie zasobów.

Równoważnie w Javie 7 lub nowszym możesz użyć składni „try-with-resources”:

try (Scanner in = new Scanner(System.in)) {
    ... 
}

2
Co oznacza wyciek zasobów i jak wpłynie to na mnie?
Erran Morad

7
@Borat - „wyciek zasobów” oznacza, że ​​część zasobów systemowych (zwykle pamięć) jest tracona lub niepotrzebnie marnowana. Zwykle będzie to miało wpływ na Ciebie, gdy zaczniesz otrzymywać OutOfMemoryErrors wyrzucane podczas normalnego działania programu.
Eric Lindauer

Dzięki Eric. Wiem, że możesz spowodować błąd, dołączając do siebie ciąg w nieskończonej pętli. Nie jestem pewien, jak skaner mógł spowodować ten błąd.
Erran Morad

4
A co z próbą z zasobami?
Dennis Meng

Dzięki, Dennis, dodał.
Eric Lindauer

12

Musisz zadzwonić in.close()w finallybloku, aby się upewnić.

Z dokumentacji Eclipse, oto dlaczego go flagi to szczególny problem ( podkreślenie moje):

Klasy implementujące interfejs java.io.Closeable (od JDK 1.5) i java.lang.AutoCloseable (od JDK 1.7) są traktowane jako reprezentujące zasoby zewnętrzne, które powinny być zamykane metodą close (), gdy nie są już potrzebne.

Kompilator Eclipse Java jest w stanie przeanalizować, czy kod używający takich typów jest zgodny z tą polityką.

...

Kompilator oznaczy [naruszenia] komunikatem „Wyciek zasobów:„ strumień ”nie jest nigdy zamknięty”.

Pełne wyjaśnienie tutaj .


7

Jest informacją, że trzeba zamknąć skaner, którego instancję na System.inz Scanner.close(). Zwykle każdy czytelnik powinien być zamknięty.

Zwróć uwagę, że jeśli zamkniesz System.in, nie będziesz mógł ponownie z niego przeczytać. Możesz również przyjrzeć się Consoleklasie.

public void readShapeData() {
    Console console = System.console();
    double width = Double.parseDouble(console.readLine("Enter the width of the Rectangle: "));
    double height = Double.parseDouble(console.readLine("Enter the height of the Rectangle: "));
    ...
}

3
Należy pamiętać, że System.console()nie jest dostępne podczas uruchamiania aplikacji za pośrednictwem Eclipse, co może być kłopotliwe podczas programowania.
Stuart Cook

6

Jeśli używasz JDK7 lub 8, możesz użyć try-catch z zasobami, co spowoduje automatyczne zamknięcie skanera.

try ( Scanner scanner = new Scanner(System.in); )
  {
    System.out.println("Enter the width of the Rectangle: ");
    width = scanner.nextDouble();
    System.out.println("Enter the height of the Rectangle: ");
    height = scanner.nextDouble();
  }
catch(Exception ex)
{
    //exception handling...do something (e.g., print the error message)
    ex.printStackTrace();
}

Należy pamiętać, że klauzula catch nie jest obowiązkowa. Jeśli chcesz tylko upewnić się, że zasób jest zamknięty nawet w przypadku wyjątku, ale pozostaw traktowanie wyjątków tak, jak w oryginalnym kodzie PO (a mianowicie, aby w ogóle nie zostały złapane), możesz po prostu użyć, tryjak pokazano, i nie używać catchklauzuli.
user118967

5
// An InputStream which is typically connected to keyboard input of console programs

Scanner in= new Scanner(System.in);

powyższa linia wywoła klasę Constructor of Scanner z argumentem System.in i zwróci referencję do nowo skonstruowanego obiektu.

Jest podłączony do strumienia wejściowego, który jest podłączony do klawiatury, więc teraz w czasie wykonywania możesz wziąć dane wejściowe użytkownika, aby wykonać wymaganą operację.

//Write piece of code 

Aby usunąć wyciek pamięci -

in.close();//write at end of code.


3

dodanie private static Scanner in; tak naprawdę nie rozwiązuje problemu, a jedynie usuwa ostrzeżenie. Uczynienie skanera statycznym oznacza, że ​​pozostanie on otwarty na zawsze (lub do wyładowania klasy, co jest prawie „na zawsze”). Kompilator nie daje już żadnych ostrzeżeń, ponieważ powiedziałeś mu „zostaw to otwarte na zawsze”. Ale to nie jest to, czego naprawdę chciałeś, ponieważ powinieneś zamykać zasoby, gdy tylko nie będziesz ich już potrzebować.

HTH, Manfred.


2

Generalnie instancje klas, które zajmują się we / wy, powinny być zamykane po ich zakończeniu. Więc na końcu kodu możesz dodać in.close().


2
private static Scanner in;

Naprawiłem to, deklarując jako prywatną zmienną statyczną klasy Scanner. Nie jestem pewien, dlaczego to naprawiło, ale to właśnie zalecało mi zaćmienie.


5
wyciszyłeś ostrzeżenie, ale spowodowałeś wyciek zasobów
zacheusz

1

Skaner powinien być zamknięty. Dobrą praktyką jest zamykanie czytników, strumieni ... i tego rodzaju obiektów w celu zwolnienia zasobów i zapobiegania wyciekom pamięci; i robiąc to w bloku final, aby upewnić się, że są one zamknięte, nawet jeśli wystąpi wyjątek podczas obsługi tych obiektów.


Ta odpowiedź faktycznie pomaga OP wiedzieć, dlaczego powinien zamknąć sprawę. Jasne, może przeczytać dokument i zobaczyć „ scanner.close()”, ale ta odpowiedź naprawdę pomaga mu zrozumieć, co się dzieje. + 1
HyperNeutrino

1

Okej, poważnie, przynajmniej w wielu przypadkach jest to faktycznie błąd. Pojawia się również w VS Code i jest to linter zauważający, że osiągnąłeś koniec otaczającego zakresu bez zamykania obiektu skanera, ale nie rozpoznając, że zamknięcie wszystkich otwartych deskryptorów plików jest częścią zakończenia procesu. Nie ma wycieku zasobów, ponieważ wszystkie zasoby są czyszczone po zakończeniu, a proces odchodzi, nie pozostawiając miejsca na przechowywanie zasobu.


0
Scanner sc = new Scanner(System.in);

//do stuff with sc

sc.close();//write at end of code.

-1
in.close();
scannerObject.close(); 

Zamknie się Scanneri wyłączy ostrzeżenie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.