web-dev-qa-db-fra.com

Java - Scanner de fermeture et fuite de ressources

J'apprends Java et je travaille sur certains projets pour le plaisir. Un problème que j'ai rencontré est que lorsque j'utilise un objet Scanner, Eclipse me prévient que:

Fuite de ressources: 'scan' n'est jamais fermé.

Donc, j'ai ajouté un scan.close(); à la fin de mon code et cela prend en charge l'avertissement. 

Le problème vient du fait que d'autres classes du même package utilisent également des objets scanner et qu'Eclipse m'indique de fermer le scanner dans ces classes, respectivement. Cependant, lorsque je le fais, il semble que tous les objets du scanner soient fermés et que des erreurs se produisent pendant l'exécution. 

Voici un exemple de ce qui cause l'erreur:

import Java.util.Scanner;
public class test2 {
    public static void main(String [] args) {
        Scanner scan = new Scanner(System.in);
        int test = 0;
        do {    
            //Do stuff
            test = scan.nextInt();
            System.out.println(test);

            scanTest scanTest = new scanTest();
            scanTest.test();
        } while (test != 0);

        scan.close();       
    }
}

import Java.util.Scanner;
public class scanTest { 
    public void test() {
        Scanner scanner = new Scanner(System.in);
        int blah = scanner.nextInt();
        System.out.println(blah);
        scanner.close();
    }
}

Une fois que le scanner est fermé dans la classe scanTest et que la boucle do dans test2 est à nouveau entrée, une erreur se produit à la ligne test = scan.nextInt();.

J'ai essayé de déplacer la création de l'objet scanner dans la boucle do pour créer un nouvel objet à chaque fois, mais l'erreur persiste. 

Je ne sais pas pourquoi cela se produit ni comment je peux m'assurer que tous mes objets d'E/S sont fermés sans rencontrer de problèmes. 

Je suis tombé sur un message qui mentionnait que lorsque System.in est fermé, je ne peux pas être rouvert. Si tel est le cas, devrais-je simplement m'assurer qu'un objet du scanner avec System.in est fermé à la fin du programme et que @ prend en charge tous les autres avertissements du scanner des autres classes? Ou est-ce que cela laisserait tous ces objets de scanner ouverts (mauvais)?

9
SuperCow

Tout d'abord, il ne s'agit pas d'une fuite de mémoire.

Deuxièmement, lorsque vous fermez un wrapper de flux, l'implémentation par défaut consiste à ce qu'il ferme le flux qu'il encapsule. Cela signifie que la première fois que vous fermez votre scanner (comme il est écrit), oui, vous fermez le fichier System.in.

En général, on voudrait éviter de fermer System.in s'ils voulaient lire à nouveau System.in. La meilleure façon de procéder dépend de votre programme. 

On peut copier les informations provenant de System.in dans un tampon quelconque, puis analyser le tampon. On pourrait ne pas fermer le scanner, le réutiliser ailleurs. On pourrait même dé-référencer le scanner pour la récupération de place et créer plusieurs nouveaux scanners sur System.in.

Ces solutions ne sont pas toutes équivalentes, certaines sont considérées beaucoup mieux que d’autres; mais tout dépend du programme appelant. Essayez quelques-uns et, si vous rencontrez un problème, ouvrez une nouvelle question StackOverflow où vous montrez les parties pertinentes de votre code, une description du problème, l'exemple fourni et le mauvais résultat (avec le résultat souhaité).

Bonne chance.

3
Edwin Buck

Oui, lorsque vous fermez un scanner, vous fermez le flux sous-jacent (dans ce cas, System.in). Pour éviter cela, créez une variable globale de scanner qui peut être utilisée par toutes les classes ou disposez d'un point central pour éteindre le scanner (juste avant que le programme se termine, ce serait idéal). 

3
Scary Wombat

Ne nommez pas tous vos scanners de la même manière. Si vous avez plusieurs dans une chose comme ceci:

import Java.util.Random;
import Java.util.Scanner;

public class DayThree {

    public static void main(String[] args) {

        **Scanner textScanner = new Scanner(System.in);**

        // boolean operands 
            //    String(or objects)   .equals()      "this".equals("that")     false
            //    primitive data types     ==          'a'=='a'   ->  true   5==6   false
            //                             !=          'a'!='a'   ->  false  5!=6   true
            //                             !            !(true)   ->  false   !(false)   true
            //                             >            5 > 4     -> true    'a' > 'b'  false
            //                              <           5 < 4     -> false
            //                              <=          
            //                              >=    
            //       &&     ->  and        5 < 6 &&  7 > 10   -> false
                        // if either side of and is false the outcome is false
            //       ||     ->  or        5 < 6  || 7 > 10     -> true
                        // if either side of or is true  the outcome is true
        //System.out.println(!(5 < 10) && (7>3) ||  (true && false || true));

        /*     <-- this is a multi line comment
            System.out.println("What is the most amazing show on tv this week? ");
            String show = textScanner.nextLine().toLowerCase();  //this is case sensitive

            show = show.toLowerCase(); // changes the strng to a lowercase version
            show = show.toUpperCase(); 

            if(show.equalsIgnoreCase("game of thrones")){ // .equalsIgnoreCase( ignores caps/lower)
                System.out.println("Yes it is!");
            }
            else{
                System.out.println("You are wrong.");
                System.out.println(show + " is clearly inferior to Game of Thrones.");
            }

            System.out.println("Who is your favorite character in " + show + ".");
            String character = textScanner.nextLine().toLowerCase();

            if(character.contains("dragon")){
                System.out.println("CGI magic is so cool!");
            }
            else if(character.contains("lanister")){
                System.out.println("Wrong house.");
            }
            else{
                System.out.println(character + "is pretty cool I guess...");
            }
        */ 
//      asdf      alternate multi line comment use ctrl + /  on highlighted text. 
//                      doing this a second time undoes the comment 
//      sdaf
//      asdf
//      asdf
//      asdf

//      1.  ask about favorite something (pet)
//      2. save that into a string all lowercase
//      3. have a series of if else (x3) and else statements about the something

        //NOTE: DO NOT END CONDITIONALS WITH ; example: if(boolean);  IS WRONG. 
        **Scanner numScanner = new Scanner(System.in);** // the variable tells you what to use it for
        Random Rand = new Random();  // this makes a new random object 
        System.out.println("Pick a number.");
        int num = numScanner.nextInt();
        int sNum = Rand.nextInt(9) + 1;  // gives me a random num between 1-10
                                        // nextInt(bound)gives you a num from 0-bound
                                        //adding one gives you a num from 1 - bound + 1
        if(num > sNum){
            System.out.println("Too high");
            System.out.println("The number was " + sNum);
        }
        else if(num < sNum){
            System.out.println("Too low");
            System.out.println("The number was " + sNum);
        }
        else{
            System.out.println("Wow are you psychic? ");
        }
        textScanner.close();
        numScanner.close();
    }//main method

}

Mettez la *scanner name goes here*.close(); pour chacun de vos scanners. S'ils portent tous le même nom, changez ceux qui font quelque chose de différent de l'autre scanner.

0
TheTNTwither James