Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Scanner.nextLine() not waiting for input

Tags:

java

I have several methods that I've used previously to accept user input and return it as a certain data type to the method that calls for it. I have used these methods, or variations of them, in previous projects.

I've adopted the method that I used for string to select the first char given and return that, so that I can use this in a menu. Every time I start the application, the main menu appears and waits for user input. After receiving this input, the program loops continuously until stopped. Here is my method for capturing the char:

private char getUserChar(String prompt) {
    try {
        Scanner scan = new Scanner(System.in);
        System.out.print(prompt);
        String tempString = "";
        tempString = scan.nextLine();
        scan.close();
        char userChar = tempString.charAt(0);
        return userChar;
    } catch(Exception ex) {
        System.out.println(ex.getMessage());
    }
    return 0;
}

The code loops due to the try/catch block, as scan.nextLine() never waits for the next input. Without it, the exception is typically related to not finding a new line. I've tried the while(scan.hasNextLine()) that seems to work for other people; however, once the time for input arrives, it never breaks out of the loop. I also don't believe I'm tripping up on the nextInt() issue that everyone seems to have troubles with. I'll post the code for the entire class below:

import java.util.Scanner;
import controller.Controller;
public class TUI {
    private Controller controller;
    public TUI() {
        Controller controller = new Controller();
        this.controller = controller;
    }

    public void run() {
        boolean wantToQuit = false;
        char userInput = 0;
        System.out.println("Welcome to the Mart.");
        do{
            userInput = mainMenu();
            if(isUserInputValid(userInput))
                switch(userInput){
                    case 'a': addItem();
                    break;
                    case 'r': controller.removeItem();
                    break;
                    case 'i': controller.printInventory();
                    break;
                    case 'p': controller.customerPurchase();
                    break;
                    case 'w': controller.weeklyStock();
                    break;
                    case 'c': wantToQuit = true;
                    break;
                }
            else System.out.println("\nMainMenu");



        } while(!(wantToQuit));
        System.out.println("WolfMart is now closed.  Thank you and good-bye.");
    }




    private boolean isUserInputValid(char userInput) {
        char[] testSet = {'a', 'r', 'i', 'p', 'c', 'w'};
        for(char currentChar : testSet) {
            if(currentChar == userInput)
                return true;
        }
        return false;
    }

    private char mainMenu() {
        System.out.println();
        controller.printInventory();
        String mainMenuSelection = "What would you like to do: (a)dd item, (r)emove item, print (i)nventory, " +
            "(p)urchase by customer, (c)lose store?\r\n";

        char mainMenuInput = getUserChar(mainMenuSelection);
        return mainMenuInput;
    }

    private char getUserChar(String prompt) {
        try {
            Scanner scan = new Scanner(System.in);
            System.out.print(prompt);
            String tempString = "";
            tempString = scan.nextLine();
            scan.close();
            char userChar = tempString.charAt(0);
            return userChar;
        } catch(Exception ex) {
            System.out.println(ex.getMessage());
        }
        return 0;
    }


    private int getUserInt(String prompt) {
        Scanner scan = new Scanner(System.in);
        int userInt = -1;
        try {
            System.out.print(prompt);
            String input = scan.nextLine();
            userInt = Integer.parseInt(input);
        }
        catch(NumberFormatException nfe) {
            System.out.println("I did not recognize your command, please try again.");
        }
        scan.close();
        return userInt;
    }

    private String getUserString(String prompt) {
        Scanner scan = new Scanner(System.in);
        String userString = null;
        try{
            System.out.print(prompt);
            userString = scan.nextLine();
        } catch(Exception ex)
        {
            System.out.println("I did not recognize your command, please try again.");
        }
        scan.close();
        return userString;
    }

    private double getUserDouble(String prompt) {
        Scanner scan = new Scanner(System.in);
        double userDouble = -1.0;
        try {
            System.out.print(prompt);
            String input = scan.nextLine();
            userDouble = Double.parseDouble(input);
        }
        catch(NumberFormatException nfe) {
            System.out.println("I did not recognize your command, please try again.");
        }
        scan.close();
        return userDouble;
    }

    private void addItem() {
        String itemName = "";
        double price;
        int quantity;
        String namePrompt = "Enter the name of the item being added to the inventory: ";
        String pricePrompt = "Enter the cost of " + itemName + ": ";
        String quantityPrompt = "Enter the quantity of " + itemName + ": ";
        itemName = getUserString(namePrompt);
        price = getUserDouble(pricePrompt);
        quantity = getUserInt(quantityPrompt);
        controller.addItem(itemName, quantity, price);
    }




}
like image 267
floppsb Avatar asked Jan 15 '23 17:01

floppsb


1 Answers

As I stated in my comment, the problem is that you're closing System.in each time you do something like this:

Scanner scan = new Scanner(System.in);
...
scan.close();

Now, look at the specification of Scanner.nextLine

Throws:

  • NoSuchElementException - if no line was found
  • IllegalStateException - if this scanner is closed

Now, since the scanner itself is not closed, an IllegalStateException will not be thrown. Instead, as you mentioned before, the other exception, "typically related to not finding a new line", -- NoSuchElementException -- is thrown.

Presuming this you're using JDK 7, you can see how this works by examining Scanner.throwFor:

if ((sourceClosed) && (position == buf.limit()))
    throw new NoSuchElementException();

Since your exception is thrown, a value of 0 is returned by getUserChar, which is then used in the run loop:

    do {
        userInput = mainMenu();
        if (isUserInputValid(userInput)) {
            ...
        } else {
            System.out.println("\nMainMenu");
        }
    } while (!wantToQuit);

Since the input is invalid, you're caught in a loop printing "\nMainMenu\n".

To correct the issue, try to use a single Scanner and don't close System.in ;-)

like image 154
obataku Avatar answered Jan 29 '23 20:01

obataku