Perdita di risorse: "in" non viene mai chiuso


86

Perché Eclipse mi dà il riscaldamento "Perdita di risorse: 'in' non è mai chiuso" nel codice seguente?

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

Risposte:


72

Perché non chiudi lo Scanner

in.close();

40
Questo chiuderà Scannere silenzierà l'avviso, ma chiuderà anche il System.inche in genere non è desiderabile.
Stuart Cook

@StuartCook +1. Qualcosa da tenere d'occhio.
informatik01

8
Perché dobbiamo chiudere Scanner? Cosa si intende per "perdita di risorse"?
Erran Morad

1
@nogard: questa tua risposta è davvero utile .. ma quando uso in.close (); .. ancora una volta non può essere risolto .. ho un codice senza gestione delle eccezioni .. grazie
pc

3
@StuartCook, hai dimenticato di dire perché la chiusura in System.ingenere non è desiderabile. È perché non sarai più in grado di leggere da esso. I. e. otterrai java.util.NoSuchElementException: No line foundse provi a chiamare, (new Scanner(System.in)).nextLine()ad esempio.
Petr Bodnár

55

Come altri hanno già detto, è necessario chiamare "close" sulle classi IO. Aggiungerò che questo è un posto eccellente per usare la prova - finalmente blocca senza cattura, in questo modo:

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

Ciò garantisce che lo scanner sia sempre chiuso, garantendo una corretta pulizia delle risorse.

In modo equivalente, in Java 7 o versioni successive, puoi utilizzare la sintassi "try-with-resources":

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

2
Cosa si intende per perdita di risorse e come influirà su di me?
Erran Morad

7
@ Borat - "perdita di risorse" implica che alcune risorse di sistema (di solito memoria) vengono perse o sprecate inutilmente. Di solito questo avrà un impatto su di te quando inizi a ricevere OutOfMemoryErrors durante il normale funzionamento del tuo programma.
Eric Lindauer

Grazie Eric. So che puoi causare l'errore aggiungendo una stringa a se stessa in un ciclo infinito. Non sono sicuro di come uno scanner possa causare quell'errore.
Erran Morad

4
Che ne dici di una prova con le risorse?
Dennis Meng

Grazie Dennis, ha aggiunto.
Eric Lindauer

12

Hai bisogno di chiamare in.close(), in un finallyblocco per assicurarti che si verifichi.

Dalla documentazione di Eclipse, ecco perché segnala questo particolare problema ( enfasi mia):

Le classi che implementano l'interfaccia java.io.Closeable (da JDK 1.5) e java.lang.AutoCloseable (da JDK 1.7) sono considerate rappresentare risorse esterne, che dovrebbero essere chiuse usando il metodo close (), quando non sono più necessarie.

Il compilatore Java di Eclipse è in grado di analizzare se il codice che utilizza tali tipi aderisce a questa politica.

...

Il compilatore contrassegnerà [violazioni] con "Perdita di risorse: 'flusso' non è mai chiuso".

Spiegazione completa qui .


7

E vi sta dicendo che è necessario chiudere lo scanner che si creata un'istanza System.incon Scanner.close(). Normalmente ogni lettore dovrebbe essere chiuso.

Nota che se chiudi System.in, non sarai più in grado di leggere da esso. Puoi anche dare un'occhiata alla Consoleclasse.

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
Notare che System.console()non è disponibile quando si esegue un'applicazione tramite Eclipse, il che può essere un problema durante lo sviluppo.
Stuart Cook

6

Se stai usando JDK7 o 8, puoi usare try-catch con le risorse. Questo chiuderà automaticamente lo scanner.

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

Si noti che la clausola catch non è obbligatoria. Se vuoi solo assicurarti che la risorsa sia chiusa anche in caso di eccezione, ma lasciare il trattamento delle eccezioni come nel codice originale dell'OP (cioè, non catturato affatto) puoi semplicemente usare trycome mostrato e non usare una catchclausola.
user118967

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

Scanner in= new Scanner(System.in);

sopra la riga richiamerà la classe Costruttore dello scanner con l'argomento System.in e restituirà un riferimento all'oggetto appena costruito.

È connesso a un flusso di input connesso alla tastiera, quindi ora in fase di esecuzione puoi prendere l'input dell'utente per eseguire l'operazione richiesta.

//Write piece of code 

Per rimuovere la perdita di memoria:

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


3

l'aggiunta private static Scanner in;non risolve realmente il problema, cancella solo l'avviso. Rendere statico lo scanner significa che rimane aperto per sempre (o fino a quando la classe non viene scaricata, il che è quasi "per sempre"). Il compilatore non ti dà più avvertimenti, dal momento che gli hai detto "tienilo aperto per sempre". Ma non è quello che volevi veramente, dal momento che dovresti chiudere le risorse non appena non ne hai più bisogno.

HTH, Manfred.


2

In genere, le istanze di classi che si occupano di I / O dovrebbero essere chiuse dopo averle terminate. Quindi alla fine del codice potresti aggiungere in.close().


2
private static Scanner in;

L'ho risolto dichiarando come variabile di classe Scanner statica privata. Non sono sicuro del motivo per cui è stato risolto, ma è quello che eclipse mi ha consigliato di fare.


5
hai disattivato l'avviso ma hai creato una perdita di risorse
zacheusz

1

Lo scanner dovrebbe essere chiuso. È una buona pratica chiudere lettori, stream ... e questo tipo di oggetti per liberare risorse e evitare perdite di memoria; e farlo in un blocco finalmente per assicurarsi che siano chiusi anche se si verifica un'eccezione durante la gestione di quegli oggetti.


Questa risposta in realtà aiuta OP a sapere perché dovrebbe chiudere la cosa. Certo, può leggere il documento e vedere " scanner.close()", ma questa risposta lo aiuta davvero a capire cosa sta succedendo. + 1
HyperNeutrino

1

Ok, seriamente, almeno in molti casi, questo è in realtà un bug. Viene visualizzato anche in VS Code ed è il linter che nota che hai raggiunto la fine dell'ambito di inclusione senza chiudere l'oggetto scanner, ma non riconosce che la chiusura di tutti i descrittori di file aperti fa parte della terminazione del processo. Non c'è perdita di risorse perché le risorse vengono tutte ripulite al termine e il processo scompare, senza lasciare alcun posto in cui la risorsa possa essere trattenuta.


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

//do stuff with sc

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

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

Chiuderà Scannere spegnerà l'avviso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.