"hasNextInt" does not detect subsequent input; where to put "nextLine"? - java

I am brand new at Java and this one is throwing me. Using the below code it loops through for the first question until I enter anything but an integer but after finishing that loop it does not stop for the remaining question.
Through a bit of research and reading I have found that I need to use the in.nextLine() to eat the newline character after the input. However no matter where I place the nextLine() it doesn't work? I thought it would be after the first int input = in.nextInt(); line but that did not work. Any help on where it would go and why?
System.out.print("How many CUs per course are remaining in your degree program? Enter any letter to quit: ");
while (in.hasNextInt()) { // Verify input is an integer
int input = in.nextInt();
if (input <= 0) // Verify that input is not negative or zero
{
System.out.println("Please enter a positive number or any letter to quit");
System.out.print("Add another course or any letter to quit: ");
} else {
courseCuList.add(input);
System.out.print("Add another course or any letter to quit: ");
}
}
System.out.print("How many CUs do you plan to take per term?");
while (in.hasNextInt()) {
int input = in.nextInt();
// in.nextLine(); This line consumes the \n
if (input <= 0) {
System.out.println("Please enter a whole positive number.");
System.out.println("How many CUs do you plan to take per term?");
} else {
cuPerTerm = in.nextInt();
}
}

Your problem is that in while (in.hasNextInt()) each call of hasNextInt needs to wait for user input, and then test if it is integer or not.
So each time user give integer, condition will be evaluated to ture, loop will execute and condition will need to be checked again, and if it is integer loop will execute again. This will go again and again until hasNextInt will be able to return false, for instance when user will give non-integer - like letter. But in this case condition in next loop will also return false because this non-integer value was not consumed after first loop. To let second loop work you would need to invoke nextLine two times
to consume line separator after previously put correct integer
to consume actual non-integer value
But this may also fail if user will not put any integer before non-integer value because there will be no line separator to consume.
So consider changing your logic to something similar to
boolean iterateAgain = true;
System.out.print("give me positive number: ");
while (iterateAgain) {
// this inner loop will move on only after getting integer
while (!in.hasNextInt()) {//here program waits for user input
in.nextLine();// consume non-integer values
System.out.print("that wasn't positive number, try again: ");
}
int number = in.nextInt();// now there must be number here
in.nextLine();// consume line separator
if (number > 0) {
System.out.println("you gave " + number);
// do what you want with this number
iterateAgain = false;// we can leave loop
} else
System.out.print("that wasn't positive number, try again: ");
}
If you want to execute next loop then all you need is reset iterateAgain value to true.

You need to read twice.
The exit condition on your while loop is hasNextInt() - checking to see if the next token is an integer doesn't actually clear that token, which means that the next nextLine() is going to read the token, and the subsequent nextLine() will read the newline character.
To demonstrate this, place the following between the loops:
System.out.println(in.nextLine() + " | " + in.nextLine());
For the input 4, 4, A, you will see the output:
How many CUs per course are remaining in your degree program? Enter any letter to quit: 4
Add another course or any letter to quit: 4
Add another course or any letter to quit: A
| A
How many CUs do you plan to take per term?
There are two tokens that need to be cleared from the buffer, and neither of them are integers. Because of this, no matter where you put nextLine(), it will fail - you need to insert it twice. If you only insert it once, the next token won't be an integer, and hasNextInt() will fail when the program tries to enter the second loop.
In order to get your program to work, simply insert:
in.nextLine(); in.nextLine();
before the second loop. (Note that you shouldn't put both this and the print-out in, as this will read four times.)

Related

What is memory buffer? And how different Scanner class methods operate on the probable issues of line breaks, white spaces etc.?

I am having trouble understanding how memory buffer works when I am working with Scanner class methods such as hasNextInt() hasNextDouble() etc. Considering the following code,
Scanner in = new Scanner(System.in);
int number;
do {
System.out.print("Enter a positive integer: ");
while (!in.hasNextInt()) {
System.out.println("It's not an integer!");
in.next();
}
number = in.nextInt();
} while (number <= 0);
System.out.println("Your number is " + number);
The output for some random values:
Enter a positive integer: five
It's not an integer!
-1
Enter a positive integer: 45
Your number is 45
What actually happens here? At line 1 when I enter five the nested while loop runs. What is the job of in.next()? After I enter five it says It's not an integer! But why doesn't it ask again: Enter a positive integer: ? Basically, I want the corresponding output to be like this:
Enter a positive integer: five
It's not an integer!
Enter a positive integer: -1
It's not a positive integer!
Enter a positive integer: 45
Your number is 45.
I would appreciate a brief and intuitive explanation how white spaces, line breaks are handled in input validation? And what is memory buffer? And how different methods of Scanner class like next(), nextLine(), nextInt(), nextDouble() etc. operate?
Also, how do I avoid repetition of It's not an integer!
Enter a positive number: five
It's not an integer!
one two three
It's not an integer!
It's not an integer!
It's not an integer!
10
Your number is 10
And finally, why many recommend try catch?
To start with, 0, -1, -66, 2352, +66, are all Integer values so you can't very well decide to designate them as otherwise. Your validation response should really be:
System.out.println("It's not a positive integer value!");
I personally never use those nextInt(), nextDouble(), etc methods unless I want blind validation. I just stick with a single loop, and utilize the nextLine() method along with the String#matches() method (with a small Regular Expression). I also don't really care for using a try/catch to solve a situation where I don't have to.
Scanner in = new Scanner(System.in);
int number = 0;
while (number < 1) {
System.out.print("Enter a positive integer (q to quit): ");
String str = in.nextLine();
if (!str.equals("") && String.valueOf(str.charAt(0)).equalsIgnoreCase("q")) {
System.exit(0);
}
// If a string representation of a positive Integer value
// is supplied (even if it's prefixed with the '+' character)
// then convert it to Integer.
if (str.matches("\\+?\\d+") && !str.equals("0")) {
number = Integer.parseInt(str);
}
// Otherwise...
else {
System.err.println(str + " is not considered a 'positive' integer value!");
}
}
System.out.println("Your number is " + number);
In this particular use-case, I actually find this more versatile but then, perhaps that's just me. It doesn't matter what is entered, you will always get a response of one form or another and, you have a quit option as well. To quit either the word quit or the letter q (in any letter case) can be supplied.
People like to utilize the try/catch in case a NumberFormatException is thrown by nextInt() because a white-space or any character other than a digit is supplied. This then allows the opportunity of displaying a message to console that an invalid input was supplied.
Because the Scanner class is passed System.in within its' constructor (in is an object of InputStream) it is a Stream mechanism and therefore contains a input (holding) buffer. When anything is typed to the Console Window it is place within the input buffer until the buffer is read by any one of the next...() methods.
Not all Scanner class methods like next(), nextInt(), nextDouble(), etc, completely utilize everything contained within the stream input buffer, for example, these methods do not consume whitespaces, tabs, and any newline characters when the ENTER key is hit. The nextLine() method however does consume everything within the input buffer.
This is exactly why when you have a prompt for a User to supply an Integer value (age) and you use the nextInt() method to get that data and then directly afterwords you prompt for a string like the User's name using the nextLine() method, you will notice that the nextLine() prompt is skipped over. This is because there is still a newline character within the input buffer that wasn't consumed by the nextInt() method and now forces the nextLine() method to consume it. That ENTER that was done in the previous nextInt() method is now passed into the nextLine() method thus giving the impression that the prompt was bypassed when in reality, it did receive a newline character (which in most cases is pretty much useless).
To overcome this particular situation the easiest thing to do is to consume the ENTER key newline character by adding scanner.nextLine(); directly after a int myVar = scanner.nextInt(); call. This then empties the input buffer before the String name = scanner.nextLine(); comes into play.

Is there a way to show an error message while the user has not entered a valid value, within the condition of a while loop

I pretty new to java programming so i was wondering if there is a way to use the condition of a while loop to stop an invalid value being used.
I am writing a program that prompts the user to enter an identification number as an integer then uses a scanner to store that value.
Just wanted to know if this is possible to put something in the condition of the for loop that prints an error message if the enter something like a string, double or char so i dont get the Input Mismatch Exception.
like this:
identification = userId(in); //scanner
while (identification (is not an integer)){
System.out.println("Invalid Value, Please enter an integer");
identification = userId(in);
Even better, you can write:
while ((identification = userId(in)) < 0) {
System.out.println("blah ...");
}
The assumption is that the userIn method returns some negative value if the input is not an integer. You can make the invalid return value whatever you want as long as it is not something that is a valid input.
Some people don't like this style because it has gone out of fashion and they are not used to it; however, it used to be common in C programming and there is nothing about it that is implicitly unclear or bad.
This should do what you are asking. It is basically a while loop that waits until the next input is an integer before continuing the code. The important part is making sure to use in.next() inside the while loop instead of in.nextInt() because the values could be anything.
Scanner in = new Scanner(System.in);
System.out.print("Enter an integer: ");
while (!(in.hasNextInt()))
{
System.out.print("Integer not entered, please enter an integer: ");
in.next();
}
int value = in.nextInt();
System.out.println("The int was " + value);
in.close();

Java Looping for user input error until it's an int/double and distinguishing between the error input

I have a problem I sort of half fixed? It's more of a logic error, I think. My program overall is running smoothly, but I need to fix the flow of how my program interprets user input.
This program should report user error if they input a non numerical value or a negative number. And if the user enters 0, then is should accept it as a correct answer ( I have yet to figure out how to do that since my condition is whether or not it's a double).
I'm trying to differentiate between whether the user inputs a negative number or a character in the feedback. So far, I've made a loop to continuously prompt the user to enter a number if they don't input a double. Though I'm not sure how to go about accepting a 0 as an answer and filtering out negative numbers. I went back to my flow diagram and figured I may need to use an if-else statement to do this. But how can I do that while keeping the loop going? I'm not totally sure how I'm suppose to format that kind of thing.
Help is appreciated for this newbie! Thank you!
while(looping){
// Prompt user to enter how many grades they want averaged
System.out.println("How many grades would you like to average? ");
// Check if the input variables are positive numerical variables
// Or else report to user to input a number
while(!input.hasNextDouble()) //cannot be negative
{
input.next();
System.out.println("Please enter a number: ");
}
gradeNumber = input.nextInt();
// Prompt user to enter the grades
System.out.println("Please enter " + gradeNumber + " grades: ");
// Use a for-loop to control how many loops - reference to gradeNumber
for(gradesCount = 0; gradesCount < gradeNumber; gradesCount++){
// Check if the input variables are numerical variables
while (!input.hasNextDouble())
{
input.next();
System.out.println("Please enter a number: ");
}
gradesInput = input.nextDouble();
finalGrades = finalGrades + gradesInput;
} // end loop

Scanner nextLine() issues

I've been working on a programming assignment that acts as a Scrabble dictionary for a while now. The program takes input from the user and outputs a file with a list of words, depending on what the user requests from a menu. The problem I've been having has to do with Scanner.nextLine().
I'm not aexactly sure why, but for some reason I have to press enter once sometimes before my code will take my input and store it as the variable. Essentially, I end up entering the input twice. I tried inserting Scanner.nextLine() around the code to "take up" the empty enter/spaces but it doesnt work, and I have to press enter multiple times to get it to process what I want.
Does anybody have any suggestions? I'd appreciate any and all help.
Here is a bit of the code:
System.out.println("Enter the length of the word you are" + " searching for.");
int n = -1;
while(!(n >=0)) {
if(in.hasNextInt())
n = in.nextInt();
else {
System.out.println("You have not entered a valid number.
Please enter a real number this time.");
in.nextLine();
}
}
in.nextLine();
System.out.println("Enter the first letter of the words" + " you are searching for.");
String firstLetter = "";
while(!(firstLetter.length() == 1)) {
if(in.nextLine().length() > 1) {
System.out.println("You have not entered a valid letter.
Please press enter and enter only one real letter.");
}
else if(in.hasNextInt()) {
System.out.println("Do not enter a number. Please enter one real letter.");
}
else {
in.nextLine();
firstLetter = in.nextLine();
break;
}
}
At the end of this, I have to press enter once and then input to get it to store anything in the variable firstLetter. I assume it has something to do with the nature of nextLine(), as the conditions using nextInt() give no issues.
It's because you're using both nextLine() and nextInt(), what's going on is that nextLine() is searching for a new line (enter) and nextInt will automatically stop the search if any integer is typed through System.in.
Rule of thumb: Just use Scanner.nextLine() for your input, then convert your string from Scanner.nextLine() accordingly through Integer.parseInt(string), etc.
I think you're overcompensating with too many nextLines. You may want to do that once to clear the line after the int is inputted, for example, to clear the newline, but the second time here just absorbs an extra line of input:
System.out.println("You have not entered a valid number. Please enter a real number this time.");
in.nextLine();//first time
}
}
in.nextLine();//this second time is unnecessary.
The same thing happens with your duplicate uses here:
in.nextLine();
firstLetter = in.nextLine();
break;
You should only add an extra in.nextLine() immediately between inputting nextSOMETHINGELSE() and another nextLine().
EDIT:
Additionally, note that whenever you call in.nextLine(), you are absorbing a line of input. For example, this line should be fixed:
if(in.nextLine().length() > 1){
because it reads in a line, using it up, and then checks whether that (now used-up) line is long enough.

my codes goes infinity loop and does not prompts the user anymore

boolean acceptPcode=true;
boolean acceptQty=false;
int Qty=0;
List<Integer> purchasedProdQty=new ArrayList<>();
while(acceptPcode==true && acceptQty==false){
do{
try{
System.out.print("Enter Qty: ");
Qty=sc.nextInt();
acceptQty=true;
}catch(InputMismatchException ime){
System.out.println("Invalid quantity please enter a number!");
acceptQty=false;
}
if(acceptQty==true)
purchaseProdQty.add(Qty);
}while(acceptQty==false);
}
my question is that when i enter a letter it goes in an infinity loop and it doesn't prompt the user to enter a quantity ....which is
Enter Qty: Invalid quantity please enter a number!
Enter Qty: Invalid quantity please enter a number!
Enter Qty: Invalid quantity please enter a number!......
You forgot to read the \n (or \r\n) characters that are from the next line. In your current code, the scanner is waiting for an int input, bu the current next input is this break line char. Just add sc.nextLine() in your code to consume the break line char:
Qty=sc.nextInt();
sc.nextLine();
acceptQty=true;
From what I can gather it seems your scanner(sc) is throwing an exception. This causes acceptQty to constantly be false keeping you stuck in your inner do-while loop.
You need to consume any illegal characters in the exception block otherwise they won't be consumed by the Scanner#nextInt method call causing the loop to repeat itself indefinitely:
} catch(InputMismatchException ime) {
System.out.println
("Invalid quantity: " + sc.nextLine() + " please enter a number ");
...
}
You are getting exception while reading out of sc and so it always go into infinity loop. Can you paste what's the value assiged in sc?
I believe you're doing this all wrong. Your method of validation is very obscure and can be simplified. Suppose you have the following method:
public int readNumber(final String prompt, final Scanner scanner){
System.out.println(prompt);
try{
return scanner.nextInt();
}catch(Exception ex){
System.err.println("Enter a valid number");
return readNumber(prompt, scanner);
}
}
This method will print out the prompt (the first argument) and read input from the provided Scanner (the second argument). If the user enters something that can't be parsed as an int, it will invoke the same method (recursion).
Take out both of your loops and when you want to read an int from your Scanner, do something like:
int value = readNumber("Enter a quantity", sc);
You know for sure that Integer.MAX_VALUE >= value >= Integer.MIN_VALUE

Categories