Scanner cannot read my input

247 Views Asked by At

When I run the following code:

class Startup (called by main()):

import java.util.ArrayList;

public class Startup {

    public void start() {

        // Build rooms
        final int WIDTH = 2;
        final int HEIGHT = 2;
        Room[][] room = new Room[WIDTH][HEIGHT];
        Rooms.build(room, WIDTH, HEIGHT);
        int x = 0;
        int y = 0;

        // Print starting room description
        Rooms.print(room, x, y);

        // Start game loop
        boolean playing = true;
        while (playing) {

            // Get user input
            String input = Input.getInput();
            System.out.println(input);

            // Movement commands
            if (input.equals("n")) {
                if (y > 0) {
                    y--;
                    Rooms.print(room, x, y);
                } else {
                    System.out.println("You can't go that way.");
                }
            }
        }
    }
}

class Input:

import java.util.Scanner;

public class Input {

    public static String getInput() {

        System.out.print("> ");
        try(Scanner in = new Scanner(System.in)) {
            String input = in.nextLine();
            input.toLowerCase();
            return input;
        }
    }
}

I will always get this NoSuchElementException:

java.util.NoSuchElementException: No line found
    at java.util.Scanner.nextLine(Scanner.java:1540)
    at Input.getInput(Input.java:11)
    at Startup.start(Startup.java:36)
    at Driver.main(Driver.java:11)

If the movement commands part in start() is removed, everything works fine. But when that part is included, that exception is always called, leading me to think that there's something wrong to it. But my question is: what's wrong?

1

There are 1 best solutions below

3
On BEST ANSWER

You are creating a new Scanner every time you call getInput. Unfortunately, you are closing it every time:

    try(Scanner in = new Scanner(System.in)) {
        String input = in.nextLine();
        input.toLowerCase();
        return input;
    }

This construct is called "Try with resources". It creates the Scanner, which is a Closeable object, and at the end of the try block, it closes it.

This means that the input stream behind the scanner is also closed.

Once you closed a stream, it cannot be re-opened. Every request for input from that stream will return the "end of file" condition. Thus, each time you open a new scanner after the first one, on the same (closed) System.in, you'll get an empty scanner which is at the "end of file".

What you need to do is open the Scanner only once. And then for the rest of the program, read from the same open scanner. To do this, you either have to have all the program inside the try-with-resources, or simply not use try-with-resources at all.