Hi,

I am having issue with the Scanner class, it seems to fall through to the next line, depending on how I call it from my class. I cannot track find a pattern to this. Except it tend to happen more when calling the nextLine() from the Scanner class.

Some info - I decided to write my self a simple class to help me with my uni work. It is just to save me writing to screen then using the scanner class to read the input. It would be easier with a one line of code and a class.

anInt = PromptGetInput.typeInt("Please enter the first int: ");

Basically I call the class with the desired method (that related to the data type that i would like to read in from the keyboard). I pass in a string as an argument and the method displays the string to the screen and then reads in the relative data type from the scanner class. The input is then returned.

Here is the class -

import java.util.*;

public class PromptGetInput
{
    private static Scanner keyb = new Scanner(System.in);

    /**
     * The method takes a String arguement and prints the string to screen.
     * The method then uses a Scanner class object to read an integer in from
     * the keyboard. <ul>Method has Input validation</ul> and loops until a
     * valid input has been achieved.
     * <p>
     * The int is automatically initialised to 0 upon declaration
     * The method returns the input integer.
     *
     * @param  String - the message that is to be displayed to screen
     * @return Int - is returned
     */
    public static int typeInt(String message)
    {
        int userInputInt = 0;
        boolean validInput = false;

        do
        {
            try
            {
                System.out.println(message);
                userInputInt = keyb.nextInt();
                validInput = true;
            }
            catch (InputMismatchException e)
            {
                System.out.println("Invalid data type.. try again");
                keyb.next();   // discard the bad input
                validInput = false;
            }

        }while(!validInput);

        //keyb.close();

        return(userInputInt);
    }

    /**
     * The method takes a String arguement and prints the string to screen.
     * The method then uses a Scanner class object to read a String in from
     * the keyboard. <ul>No input validation on this method</ul>.
     * <p>
     * The String is automatically initialised to a blankspace upon declaration
     * The method returns the input String.
     *
     * @param  String - the message that is to be displayed to screen
     * @return String - is returned
     */
    public static String typeString(String message)
    {
        //String userInputString = new String(" ");
        boolean validInput = false;

        System.out.println(message);
        String userInputString = keyb.nextLine();

        //keyb.close();

        return(userInputString);
    }

    /**
     * The method takes a String arguement and prints the string to screen.
     * The method then uses a Scanner class object to read a char in from
     * the keyboard. <ul>No Input validation</ul> the method, trims leading
     * whitespace and returns the first character.
     * <p>
     * The char is automatically initialised to a blankspace upon declaration
     * The method returns the input char.
     *
     * @param  String - the message that is to be displayed to screen
     * @return char - is returned
     */
    public static char typeChar(String message)
    {
        //char userInputChar = ' ';
        boolean validInput = false;

        System.out.println(message);
        char userInputChar = keyb.nextLine().trim().charAt(0);
        validInput = true;

        //keyb.close();
        
        return(userInputChar);
    }

    /**
     * The method takes a String arguement and prints the string to screen.
     * The method then uses a Scanner class object to read a float in from
     * the keyboard. <ul>Method has Input validation</ul> and loops until a
     * valid input has been achieved.
     * <p>
     * The float is automatically initialised to 0 upon declaration
     * The method returns the input float.
     *
     * @param  String - the message that is to be displayed to screen
     * @return float - is returned
     */
    public static float typeFloat(String message)
    {
        float userInputFloat = 0;
        boolean validInput = false;

        do
        {
            try
            {
                System.out.println(message);
                userInputFloat = keyb.nextFloat();
                validInput = true;
            }
            catch (InputMismatchException e)
            {
                System.out.println("Invalid data type.. try again");
                keyb.next();   // discard the bad input
                validInput = false;
            }

        }while(!validInput);

        //keyb.close();

        return(userInputFloat);
    }

    /**
     * The method takes a String arguement and prints the string to screen.
     * The method then uses a Scanner class object to read a double in from
     * the keyboard. <ul>Method has Input validation</ul> and loops until a
     * valid input has been achieved.
     * <p>
     * The double is automatically initialised to 0.0 upon declaration
     * The method returns the input double.
     *
     * @param  String - the message that is to be displayed to screen
     * @return double - is returned
     */
    public static double typeDouble(String message)
    {
        double userInputDouble = 0.0;
        boolean validInput = false;
        
        do
        {
            try
            {
                System.out.println(message);
                userInputDouble = keyb.nextDouble();
                validInput = true;
            }
            catch (InputMismatchException e)
            {
                System.out.println("Invalid data type.. try again");
                keyb.next();   // discard the bad input
                validInput = false;
            }

        }while(!validInput);

        //keyb.close();

        return(userInputDouble);
    }
}

/*Here is the main that i am testing it with - */

public class PromptGetTest
{
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        int testInt;
        char testChar;
        String testString;
        float testFloat;
        double testDouble;

        testInt = PromptGetInput.typeInt("Give me an Int");
        System.out.println(testInt);

        testFloat = PromptGetInput.typeFloat("Give me an float");
        System.out.println(testFloat);
        
        testDouble = PromptGetInput.typeDouble("Give me an double");
        System.out.println(testDouble);

        testString = PromptGetInput.typeString("Give me an String");
        System.out.println(testString);        

        testChar = PromptGetInput.typeChar("Give me a char");
        System.out.println(testChar);
 
        return;
    }
}

Here is the output -

run:
Give me an Int
33
33
Give me an float
3.3
3.3
Give me an double
2.222
2.222
Give me an String <--- see how it fall straight through here

Give me a char
ssss
s

--

If I call the typeChar straight after the typeInt then I get an error which is this -

run:
Give me an Int
33
33
Give me a char <--- fell straight though here.
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at java.lang.String.charAt(String.java:687)
at PromptGetInput.typeChar(PromptGetInput.java:102)
at PromptGetTest.main(PromptGetTest.java:30)
Java Result: 1
BUILD SUCCESSFUL (total time: 2 seconds)

Ok hope someone can help..
Thanks guys..
Nate

For the typeString method, you don't want to use nextLine(). You just want to use next(). nextLine() gets the NEXT LINE. If you have 2 lines of a String i.e., "I'm line 1 \n I'm line 2", it will return " I'm line 2". next() returns everything (I believe....).

For the typeChar(), you should use next() as well. Also, consider sending the String to a char[] and accessing element 0 instead of using trim()....

Hope that helps!

For the typeString method, you don't want to use nextLine(). You just want to use next(). nextLine() gets the NEXT LINE. If you have 2 lines of a String i.e., "I'm line 1 \n I'm line 2", it will return " I'm line 2". next() returns everything (I believe....).

For the typeChar(), you should use next() as well. Also, consider sending the String to a char[] and accessing element 0 instead of using trim()....

Hope that helps!

Work in some ways.. but not in others.

.nextLine() help as it read in the next word, but not the next line eg and there is a carry over of character left in the scanner.. which gets carried into the next method.

output to explain this -
run:
Give me an Int
3
3
Give me a char
a
a
Give me an float
3.3
3.3
Give me an double
.999999
0.999999
Give me an String <-- Only grabs to the space
A String !!!!
A
Give me a char <--- s is carried over
S

------- More examples of carry over ---------

Give me an Int <---- the
3 3 3 3
3
Give me a char
3
Give me an float
3.0
Give me an double
3.0
Give me an String

---------
I tried this in the typeString method but it gets stuck in an endless loop -

public static String typeString(String message)
    {
        String addString = new String();
        String userInputString = new String(" ");
        boolean validInput = false;

        System.out.println(message);

        do
        {
            userInputString = keyb.next();
            addString += userInputString;
        }while(!keyb.hasNext(" "));

        return(userInputString);
    }

It adds all the string together.. but then just loops.. sitting there doing nothing.

Any ideas anyone?

Hi
Do it have to be done whit Scanner?
If not, use SavitchIn instead it will take care of things like wrong input for you as in the example below. (Google for the code, compile it and put it in the same folder/map as your own class.)

Example output #1:
Give me an Int
w
Your input number is not correct.
Your input number must be
a whole number written as an
ordinary numeral, such as 42
Please, try again.
Enter a whole number:
42
42

Example output #2:

Give me a float
23 34 45
Your input number is not correct.
Your input number must be
an ordinary number either with
or without a decimal point,
such as 42 or 9.99
Please, try again.
Enter a whole number:
5.67
5.67

Example output #3:
Give me a String
Hello i am a string!
Hello i am a string!

Example output #4:
Give me a char
hello again
h

I have used your code and replaced Scanner whit SavitchIn and then it looks like this:

import java.util.*;

public class InputAnotherVersion
{ 
    public static void main(String[] args)
    {
	int testInt;
	char testChar;
	String testString;
	float testFloat;
	double testDouble;

	testInt = InputAnotherVersion.typeInt("Give me an Int");
	System.out.println(testInt);

	testFloat = InputAnotherVersion.typeFloat("Give me a float");
	System.out.println(testFloat);

	testDouble = InputAnotherVersion.typeDouble("Give me a double");
	System.out.println(testDouble);

	testString = InputAnotherVersion.typeString("Give me a String");
	System.out.println(testString);

	testChar = InputAnotherVersion.typeChar("Give me a char");
	System.out.println(testChar);

	return;
    }

    public static int typeInt(String message)
    {
	int userInputInt = 0;
	
	System.out.println(message);
	userInputInt = SavitchIn.readLineInt();
     
	return(userInputInt);
    }

    public static String typeString(String message)
    {
	String userInputString = new String();
	
	System.out.println(message);
        userInputString = SavitchIn.readLine();

	return(userInputString);
    }

    public static char typeChar(String message)
    {
	char userInputChar;
 
	System.out.println(message);
        userInputChar = SavitchIn.readLineNonwhiteChar();
	
	return(userInputChar);
    }

    public static float typeFloat(String message)
    {
	float userInputFloat = 0;

	System.out.println(message);
	userInputFloat = SavitchIn.readLineFloat();
	
	return(userInputFloat);
    }

    public static double typeDouble(String message)
    {
	double userInputDouble = 0.0;

	System.out.println(message);
	userInputDouble =  SavitchIn.readLineDouble();
	
	return(userInputDouble);
    }
}

Here is an implementation of what I think llemes4011 was talking about.

See http://java.sun.com/javase/6/docs/api/java/util/Scanner.html
and
http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html

public static char typeChar(String message)
    {

        boolean validInput = false;
        char userInputChar = 0;

        System.out.println(message);
        //don't use this one because it ignores
        //possible user input
        //char userInputChar = keyb.next().trim().charAt(0);
        do
        {
            try
            {
               //use regular expression pattern to limit input
               //to String with length = 1
               //convert to a char array using "toCharArray"

               //throws exception if more than 1 "char" is entered
               char [] userInputCharArray = keyb.next(".").toCharArray();

               //copy our "character" to a char variable
               userInputChar = userInputCharArray[0];
               validInput = true;

            }
            catch (InputMismatchException e)
            {
                System.out.println("Invalid data type.. try again");
                keyb.next();   // discard the bad input
                validInput = false;

            }
        }while (!validInput);
        
        //keyb.close();

        return(userInputChar);
    }

Jesus,..

Here I am writing out this class and Savitch (the writer of my testbook has his own class, which is a like mine.. oh well.

In reply to my issue - I was informed that if I used a .nextLine() method call at the end of each of the number related methods then that would clear out the garbage from the Scanner object. This worked a treat and everything is functioning now.

Thanks for your help!

This should work for typeString. I recommend reading more about "regular expressions".

Here's a start: http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html

public static String typeString(String message)
{
    //String userInputString = new String(" ");
    boolean validInput = false;
    String userInputString = "";

    //keyb.useDelimiter(System.getProperty("line.separator"));
        
    //The default whitespace delimiter used by a scanner is as
    //recognized by Character.isWhitespace
    //change it to check for (all possible) line terminators
    keyb.useDelimiter("[\n]|[\r\n]|[\u2028]|[\u2029]|[\u0085]|[\r\n\u2028\u2029\u0085]");

    do
    {
        try
        {
         System.out.println(message);
         //next reads the next token
         //a token is "terminated" by a delimiter
         //which we changed above
         userInputString = keyb.next();
         validInput = true;
        }
        catch (InputMismatchException e)
        {
            System.out.println("Invalid data type.. try again");
            keyb.next();   // discard the bad input
            validInput = false;
        }

    }while(!validInput);

    //reset the delimiter to the default
    keyb.reset();
    //keyb.close();

    return(userInputString);
}

A more simple (and perhaps better) approach would just be to change your declaration in line #6
FROM

private static Scanner keyb = new Scanner(System.in);

TO:

//change delimiter from white space (default) to line terminator
    private static Scanner keyb = new Scanner(System.in).useDelimiter("[\n]|[\r\n]|[\u2028]|[\u2029]|[\u0085]|[\r\n\u2028\u2029\u0085]");;

If you do this, delete any references to "keyb.useDelimiter" in my above postings as well as references to "keyb.reset()". Then it should be unneccessary to add "...nextLine() method call at the end of each of the number related methods..."

This article has been dead for over six months. Start a new discussion instead.