Hi all,
I'm having some issues with the Scanner not waiting for input from the keyboard.
The first method processChoice takes the userChoice and the idea is that in the switch statement there is a call to a method getUserInputForProcessing that takes the action and there scanner takes an input but it's not passing the control to the keyboard,
it goes directly to the Exception because nextLine is empty, not entirely sure why. Is that because it's inside a switch statement?

public void processChoice(int userChoice, BookManager bookManager) {
        switch(userChoice) {
            case 0:
                System.out.println("Goodbye.");
                System.exit(0);
                break;
            case 1:
                System.out.println("You chose READ");
                getUserInputForProcessing("READ");
                bookManager.read();
                break;
            case 2:
                System.out.println("You chose CREATE");
                bookManager.create();
                break;
            case 3:
                System.out.println("You chose UPDATE");
                bookManager.update();
                break;
            case 4:
                System.out.println("You chose DELETE");
                getUserInputForProcessing("DELETE");

                bookManager.delete();
                break;

        }

    }

    public  String getUserInputForProcessing(String action)
    {

        Scanner scanner = new Scanner(System.in);
        System.out.printf("You chose %s: ", action);
        String nextLine = "";

        if(action.equals(READ) || action.equals(DELETE) )
        {
            System.out.println("Enter the searching criterion");
        }
        try
        {
            nextLine = scanner.nextLine();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        scanner.close();
        return nextLine;
    }

Recommended Answers

All 9 Replies

Line 38 raises my question. Where is the variable READ defined? Or was that supposed to be a quoted string?

If you call that method twice you wil get problems. By closing then re-opening a new Scanner on the same input stream you lose all control over what is or isn't in the buffers of each Scanner and/or he underlying stream. Lost input is pretty much guaranteed.
The general rules is create one Scanner at startup and use it for all your console input throughout the program.

ps: Scanner comes with its own set of problems, eg the infamous nextInt/nextLine trap. (If I were a betting man I would bet that you have fallen into that anyway - does the userChoice value come froma Scanner nextInt?)
If you are just reading lines then you're better off with a simple BufferedReader.

pps: following on from rproffit: presumably READ and DELETE are defined as static finals somewhere? In which case use them in lines 9 and 22

@JC, if they were declared then I'd expect them to be used on lines 9 and 22 as well. As it stands, only the OP can tell us what's up.

commented: I think that's what I said! +15

yes they are constant declared at the beginning - sorry I didn't post the whole class. And yes, I should probably use them at line 9 and 2 as pointed out.
I will use only one scanner then - at the moment I'm using 2 in fact even though they're duly closed - and then post back the results and see how it goes.

at the moment I'm using 2 in fact even though they're duly closed

Closing a System.in Scanner is not just useless, it's a problem. System.in buffers input and so do Scanners. When you close a Scanner anything that happens to be in its buffers is lost. You will never get that user input back. Even if its only a carriage return thats enough to screw up the following attempts ro read the next input.

thanks. I only closed the scanner as eclipse was somplaining about that. I remove the close statments and now everything work. However I will use only one scanner as you suggested.
Thanks

that said, using onnly one scanner appears to be causing issues again as control doesn't stop at the second scanner input inside getUserInputForProcessing.

package com.test.userInteraction;

import java.util.InputMismatchException;
import java.util.Scanner;

import com.test.db.operations.BookManager;

public class UserInput {
    private static final String READ = "READ";
    private static final String CREATE = "CREATE";
    private static final String UPDATE = "UPDATE";
    private static final String DELETE = "DELETE";
    private static final Scanner scanner = new Scanner(System.in);

    public int getUserInput() {
        //Scanner scanner = new Scanner(System.in);
        int choice = 0;
        boolean isValidInput = false;
        System.out.printf("Welcome. Select action: %d for READ, %d for CREATE, %d for UPDATE, %d for DELETE.", OperationOptions.READ.getValue(), OperationOptions.CREATE.getValue(), OperationOptions.UPDATE.getValue(), OperationOptions.DELETE.getValue());
        while(!isValidInput)
            try {                 
                choice = scanner.nextInt();
                isValidInput = true;
            }
            catch(InputMismatchException e) {
                 System.out.println("value must contain only number");
                 isValidInput = false;
                 scanner.nextLine();                 
            }
        return choice;
    }

    public void processChoice(int userChoice, BookManager bookManager) {
        switch(userChoice) {
            case 0:
                System.out.println("Goodbye.");
                System.exit(0);
                break;
            case 1:
                System.out.println("You chose READ");
                getUserInputForProcessing(READ);
                bookManager.read();
                break;
            case 2:
                System.out.println("You chose CREATE");
                bookManager.create();
                break;
            case 3:
                System.out.println("You chose UPDATE");
                bookManager.update();
                break;
            case 4:
                System.out.println("You chose DELETE");
                getUserInputForProcessing(DELETE);

                bookManager.delete();
                break;

        }

    }

    public  String getUserInputForProcessing(String action)
    {

        //Scanner scanner = new Scanner(System.in);
        System.out.printf("You chose %s: ", action);
        String nextLine = "";

        if(action.equals(READ) || action.equals(DELETE) )
        {
            System.out.println("Enter the searching criterion");
        }
        try
        {
            nextLine = scanner.nextLine();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }

        return nextLine;
    }
}

Scanner comes with its own set of problems, eg the infamous nextInt/nextLine trap

Just like I said.

Using two Scanners with closing causes you to lose the newline char that's left in the first Scanner's buffer after the nextInt.
BUT ironically as it happens discarding a newline is exactly the fix for the infamous nextInt/nextLine trap that you have fallen in to!

Here's the boilerplate explanation that I get to post on Daniweb at least once every year...

It's a real problem with Scanner's design - so many people fall into this trap.
You have some input with an int followed by some text, eg
101
John Doe
... and you try to read it with
int num = scanner.nextInt();
String name = scanner.nextLine();
... and name is an empty String ("")!

Here's why:
Your input looks like this with the new line characters shown explicitly
101\nJohn Doe\n
nextInt takes the int value from the scanner, and stops when it finds a chaacter that's not part of an int, so it takes the "101", leaving this in the scanner
"\nJohn Doe\n"
then nextLine takes everything up to the first \n character - a zero-length String ("").

Possible fixes:

  1. Add add extra nextLine() between the nextInt and the real nextLine to clear the unwanted \n. This may be difficult if the nextInt and the nextLine are in different areas of code which are not always executed together.

  2. Give up on nextInt (etc) and just read whole lines and parse then into ints (etc) with Integer.parseInt (etc) - in which case you can junk the whole scanner and use a BufferedReader instead.
    new BufferedReader(new InputStreamReader(System.in))

  3. Use this class instead of Scanner:
    https://www.daniweb.com/programming/code/506346/a-simpler-safer-alternative-to-java-util-scanner

thanks for taking the time to explain it. Yes, I got it now :-).
I went for solution 1 and it's all working now :-)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.