web-dev-qa-db-fra.com

Scanneurs multiples Java

J'ai une classe qui crée plusieurs objets Integer et les met dans un LinkedList comme indiqué ci-dessous:

public class Shares<E> implements Queue<E> {
    protected LinkedList<E> L;

    public Shares() {
        L = new LinkedList<E>();
    }

    public boolean add(E price) {
        System.out.println("How many of these shares would you like?");
        Scanner scanInt;
        scanInt = new Scanner(System.in);
        Integer noShares = scanInt.nextInt();
        for (int i = 0; i < noShares; i++) {
            L.addLast(price);
        }
        scanInt.close();

        return true;
    }
}

J'ai une application qui analyse l'entrée "add" de la console et, si elle est trouvée, appelle la méthode add comme indiqué ci-dessous:

public class Application {
    private static Scanner scan;

    public static <E> void main(String[] args) {
        Queue<Integer> S = new Shares<Integer>();
        scan = new Scanner(System.in);
        System.out.println("Please type add");
        String sentence = scan.nextLine();
        while (sentence.equals("quit") == false) {
            if (sentence.equals("add")) {

                System.out
                    .println("What price would you like to buy your shares at?");

                S.add((Integer) scan.nextInt());

            } else
                System.exit(0);

            sentence = scan.nextLine();
        }
    }
}

L’application doit permettre à l’utilisateur de saisir «ajouter» autant de fois qu’il le souhaite, mais l’erreur «Aucune ligne trouvée» apparaît après l’appel de la méthode add.

J'imagine que c'est parce que la variable Scanner de la méthode n'a pas été fermée, puis rouverte au besoin. Est-ce que c'est ce qui ne va pas avec le programme et si oui, comment pourrais-je m'y prendre pour le réparer?

S'il vous plaît noter que ce programme n'est pas terminé, car je vais ajouter une méthode de vente qui vend ces actions. C'est pourquoi j'utilise une boucle while.

11
Ryan Gibson

Avoir plusieurs wrappers pour chaque flux est un excellent moyen de vraiment vous dérouter. Je vous suggère de n'envelopper un flux qu'une seule fois, à moins de savoir vraiment ce que vous faites.

Pour ce faire, le moyen le plus simple consiste à utiliser un singleton dans ce cas car il en entoure un autre (le mieux est de passer le scanner sous forme d'argument).

public class Application { 
    // use this Scanner in all you other code, don't create another one.
    static final Scanner scan = new Scanner(System.in);

    public static <E> void main(String[] args) {

Je suppose que c'est parce que le scanner de la méthode n'a pas été fermé 

Une fois que vous fermez un flux, le flux sous-jacent est fermé et vous ne pouvez plus l'utiliser. Ne fermez System.in que si vous souhaitez empêcher son utilisation ultérieure.

comment pourrais-je m'y prendre pour le réparer?

La meilleure solution consiste à utiliser tout votre scanner dans un seul endroit, une seule méthode ou une seule classe. Vous avez votre main () faire toute l’interaction avec l’utilisateur et transmettre les valeurs à votre structure de données. Avoir des objets qui s'initialisent eux-mêmes est une mauvaise pratique et si vous commencez à le faire, cela vous gênera pour le reste de vos jours de développement;)


BTW Ne quittez jamais un programme sans explication. Appeler System.exit(0); sans même un message d'erreur est aussi un cauchemar. J'ai déjà travaillé sur un projet comportant 260 appels à System.exit () souvent sans message d'erreur. Vous pouvez donc imaginer à quel point il est amusant de diagnostiquer un serveur en train de s'arrêter, sans raison apparente.

12
Peter Lawrey

Une première erreur est que cette ligne de code 

scanInt.close();

ferme le fichier System.in, pas seulement l'objet scanInt. Cela signifie qu'après le premier appel à ajouter, l'objet à analyser ne consommera que l'entrée qu'il a déjà, puis vous recevrez une exception NoSuchElementException: Supprimez cette ligne.

Maintenant, si vous remplacez la dernière ligne que vous avez avec cette

sentence = scan.nextLine();
System.out.println("sentence: \"" + sentence + "\"");

vous verrez que la dernière entrée que vous obtenez avant de quitter est une chaîne vide. Ainsi, dans la boucle suivante, entrez l'instruction else et votre programme arrête l'exécution. Vous pouvez résoudre ce problème en ajoutant ce qui suit:

scan.nextLine(); // consume the first always empty String...
System.out.println("Please type add");
sentence = scan.nextLine(); // and then get the actual value

Cependant, je conviens avec Peter que vous ne devez pas utiliser plusieurs wrappers. Envisagez de passer l'objet Scanner en tant qu'argument dans l'entrepreneur de la classe Shares. 

6
nelly

Je sais que ceci est un article plus ancien, mais je voulais juste ajouter un court exemple de ce qui pourrait se produire lorsque vous essayez d'utiliser deux objets Scanner avec le même flux:

public static void main (String [] args) {
    Scanner scan = new Scanner(System.in);
    Scanner scan2 = new Scanner(System.in);

    System.out.println("First: "+scan.nextLine());
    System.out.println("Second: "+scan2.nextLine());

    scan.close(); // Only one scanner is closed, but...

    System.out.println("Third: "+scan2.nextLine()); // Trying to use the other scanner will throw an exception
}
0
LAD

Avoir plusieurs scanners (sur le même flux) est une très mauvaise pratique, car les scanners consomment le flux qu'ils partagent.

J'ai vérifié lors du débogage du code source et de l'examen de la classe Scanner que j'ai trouvée:

  • une référence au flux d'entrée source
  • un tampon privé interne utilisé pour contenir l'entrée.

Ainsi, lorsqu'une instance de scanner consomme son flux, elle lit en principe quelques octets (1024) et la position du flux est avancée.

Par exemple, lorsque la méthode nextLine() est appelée, source.read() copie en arrière-plan le résultat dans le tampon privé.

Il est évident que l'état d'un autre scanner est corrompu (invalide).

Essayez de déboguer le code source Java vous-même et/ou consultez la méthode Scanner.readInput() .

0
freedev