Ressourcenleck: 'in' wird niemals geschlossen


84

Warum gibt mir Eclipse im folgenden Code die Erwärmung "Ressourcenleck: 'in' wird nie geschlossen"?

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();

Antworten:


68

Weil Sie Ihren Scanner nicht schließen

in.close();

38
Dadurch wird Scannerdie Warnung geschlossen und stummgeschaltet, es wird jedoch auch geschlossen, System.inwas normalerweise nicht wünschenswert ist.
Stuart Cook

@StuartCook +1. Etwas, das man im Auge behalten sollte.
informatik01

6
Warum müssen wir den Scanner schließen? Was ist mit "Ressourcenleck" gemeint?
Erran Morad

1
@nogard: das ist deine Antwort wirklich hilfreich .. aber wenn ich in.close () verwende; .. wieder zeigt es in kann nicht aufgelöst werden .. ich habe einen Code ohne Ausnahmebehandlung .. danke
pcs

3
@StuartCook, Sie haben vergessen zu erwähnen, warum das Schließen System.innormalerweise nicht wünschenswert ist. Das liegt daran, dass Sie nicht mehr daraus lesen können. I. e. Sie erhalten, java.util.NoSuchElementException: No line foundwenn Sie versuchen, (new Scanner(System.in)).nextLine()zum Beispiel anzurufen .
Petr Bodnár

54

Wie andere bereits gesagt haben, müssen Sie bei E / A-Klassen "Schließen" aufrufen. Ich werde hinzufügen, dass dies ein ausgezeichneter Ort ist, um den Versuch zu nutzen - endlich ohne Fang zu blockieren, so:

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();
    }
}

Dies stellt sicher, dass Ihr Scanner immer geschlossen ist, und gewährleistet eine ordnungsgemäße Bereinigung der Ressourcen.

Entsprechend können Sie in Java 7 oder höher die Syntax "Try-with-Resources" verwenden:

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

2
Was ist mit Ressourcenleck gemeint und wie wirkt es sich auf mich aus?
Erran Morad

7
@Borat - "Ressourcenleck" bedeutet, dass eine Systemressource (normalerweise Speicher) verloren geht oder unnötig verschwendet wird. Normalerweise wirkt sich dies auf Sie aus, wenn Sie OutOfMemoryErrors während des normalen Betriebs Ihres Programms auslösen.
Eric Lindauer

Danke Eric. Ich weiß, dass Sie den Fehler verursachen können, indem Sie eine Zeichenfolge in einer Endlosschleife an sich selbst anhängen. Ich bin nicht sicher, wie ein Scanner diesen Fehler verursachen könnte.
Erran Morad

4
Was ist mit einem Versuch mit Ressourcen?
Dennis Meng

Danke Dennis, fügte hinzu.
Eric Lindauer

12

Sie müssen in.close()in einem finallyBlock aufrufen , um sicherzustellen, dass es auftritt.

Von der Eclipse - Dokumentation, hier ist , warum es Flags dieses besondere Problem ( Betonung von mir):

Klassen, die die Schnittstelle java.io.Closeable (seit JDK 1.5) und java.lang.AutoCloseable (seit JDK 1.7) implementieren , stellen externe Ressourcen dar, die mit der Methode close () geschlossen werden sollten, wenn sie nicht mehr benötigt werden.

Der Eclipse Java-Compiler kann analysieren, ob Code, der solche Typen verwendet, dieser Richtlinie entspricht.

...

Der Compiler kennzeichnet [Verstöße] mit "Ressourcenleck: 'Stream' wird niemals geschlossen".

Vollständige Erklärung hier .


7

Es ist Ihnen zu sagen , dass Sie den Scanner Sie instanziiert schließen müssen auf System.inmit Scanner.close(). Normalerweise sollte jeder Leser geschlossen sein.

Beachten Sie System.in, dass Sie beim Schließen nicht mehr lesen können. Sie können sich auch die ConsoleKlasse ansehen .

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
Beachten Sie, dass dies System.console()nicht verfügbar ist, wenn eine Anwendung über Eclipse ausgeführt wird. Dies kann während der Entwicklung problematisch sein.
Stuart Cook

6

Wenn Sie JDK7 oder 8 verwenden, können Sie Try-Catch mit Ressourcen verwenden. Dadurch wird der Scanner automatisch geschlossen.

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();
}

Beachten Sie, dass die catch-Klausel nicht obligatorisch ist. Wenn Sie nur sicherstellen möchten, dass die Ressource auch im Falle einer Ausnahme geschlossen ist, aber die Behandlung von Ausnahmen wie im ursprünglichen Code des OP belassen (dh überhaupt nicht abgefangen), können Sie einfach trywie gezeigt verwenden und keine catchKlausel verwenden.
user118967

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

Scanner in= new Scanner(System.in);

Die obige Zeile ruft den Konstruktor der Scannerklasse mit dem Argument System.in auf und gibt einen Verweis auf das neu erstellte Objekt zurück.

Es ist mit einem Eingabestream verbunden, der mit der Tastatur verbunden ist, sodass Sie jetzt zur Laufzeit Benutzereingaben vornehmen können, um den erforderlichen Vorgang auszuführen.

//Write piece of code 

So entfernen Sie den Speicherverlust -

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


3

Durch Hinzufügen private static Scanner in;wird das Problem nicht wirklich behoben, sondern nur die Warnung gelöscht. Wenn Sie den Scanner statisch machen, bleibt er für immer geöffnet (oder bis die Klasse entladen wird, was fast "für immer" ist). Der Compiler gibt Ihnen keine Warnung mehr, da Sie ihm gesagt haben, "halten Sie es für immer offen". Aber das ist nicht das, was Sie wirklich wollten, da Sie Ressourcen schließen sollten, sobald Sie sie nicht mehr benötigen.

HTH, Manfred.


2

Im Allgemeinen sollten Instanzen von Klassen, die sich mit E / A befassen, geschlossen werden, nachdem Sie mit ihnen fertig sind. Am Ende Ihres Codes können Sie also hinzufügen in.close().


2
private static Scanner in;

Ich habe es behoben, indem ich mich als private statische Scanner-Klassenvariable deklariert habe. Ich bin mir nicht sicher, warum das behoben wurde, aber genau das hat Eclipse empfohlen.


5
Sie haben die Warnung stummgeschaltet, aber ein Ressourcenleck erstellt
zacheusz

1

Der Scanner sollte geschlossen sein. Es wird empfohlen, Readers, Streams ... und diese Art von Objekten zu schließen, um Ressourcen freizugeben und Speicherlecks zu vermeiden. und dies in einem finally-Block, um sicherzustellen, dass sie geschlossen sind, auch wenn beim Behandeln dieser Objekte eine Ausnahme auftritt.


Diese Antwort hilft OP tatsächlich zu wissen, warum er das Ding schließen sollte. Sicher, er kann das Dokument lesen und " scanner.close()" sehen, aber diese Antwort hilft ihm wirklich zu verstehen, was los ist. + 1
HyperNeutrino

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

//do stuff with sc

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

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

ScannerDie Warnung wird geschlossen und geschlossen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.