Reading input using Scanner causes an infinite loop in Java [duplicate] - java

This question already has answers here:
How to handle infinite loop caused by invalid input (InputMismatchException) using Scanner
(5 answers)
Closed 5 years ago.
In my program I'm trying to get a user to input an int between 1-3 and then do something based off what they type. If it is not a number or not one of the options then it will allow them to reenter a valid option.
The issue I have is I'm having trouble brainstorming how to not have it infinitely loop and just allow them to enter in a number after the console tells them they entered an invalid input.
int i = 0;
while (i < 1) {
try {
int level = scan.nextInt();
i+=1;
if (level == 1) {
System.out.println("You selected level 1!");
//Start the game
} else if (level == 2) {
System.out.println("You selected level 2!");
//Start the game
} else if (level == 3) {
System.out.println("You selected level 3!");
//Start the game
} else {
System.out.println("That's not an option!");
i-=1;
}
} catch(InputMismatchException input) {
System.out.println("That's not an option!");
i-=1;
}
}

When you input an invalid input, you need to clear it. Add scan.next() when input exception triggered so as to clear it with next():
catch(InputMismatchException input) {
System.out.println("That's not an option!");
scan.next();
i-=1;
}

Not quite the answer you were expecting, but: refactor this code. Remember the basics of java, where every functional bit has its own method. So use a method that reads the input, and returns the level selected (or -1 if nothing):
int readInput() {
// your code here, returning either the level or -1 on bad input
}
And then call that for your read loop:
int selected;
do {
selected = readInput();
} while(selected < 1);

You are better off writing the code like this:
while(true){
try{
int level = scan.nextInt();
if(level==1){
System.out.println("You selected level 1!");
break;
}else if(level==2){
System.out.println("You selected level 2!");
break;
}else if(level==3){
System.out.println("You selected level 3!");
break;
}else{
System.out.println("That's not an option!");
continue;
}
}catch(InputMismatchException input){
System.out.println("That's not an option!");
continue;
}
}
continue will immediately resume execution of the loop at the top, and break will immediately jump too the closing brace } of the while. This removes the use of the i counter variable, which was entirely useless to the code. Also, this code will never run indefinitely, unless the user indefinitely enters improper values!
Hope this helped, good luck!

You can proceed in a much simpler way. The 3 valid cases are very similar and can be treated as one, the game can be started only once after the loop because we know that once the loop exits, level has a valid value.
boolean valid = false;
int level;
do {
try {
level = scan.nextInt();
valid = 1 <= level && level <= 3;
if (valid) {
System.out.println(String.format("You selected level %d !",level));
} else {
System.out.println("That's not an option!");
}
} catch(InputMismatchException input) {
scan.next();
System.out.println("That's not an option!");
}
} while (!valid);
// start the game

Related

Basic Java HiLow guessing game

I am fully aware this question has been asked many times, it is a classic first year problem in CSC. I am not looking for the solution to the problem itself. I think I have it basically done however I am missing something that I cannot find how to do.
Here is my code:
import java.util.Scanner;
import java.util.Random;
public class HiLow
{
public static void main (String[] args)
{
Random generator = new Random();
Scanner scan = new Scanner(System.in);
int num1,guess;
int count = 0;
num1 = generator.nextInt(100) + 1;
while(true) {
System.out.print("Enter an integer between 1 or 100 or enter 0 at anytime to quit: ");
guess = scan.nextInt();
count++;
if(guess == num1 || guess == 0) {
if(guess == 0) {
System.out.println("Thanks for playing");
break;
}
System.out.println("Congrats you've guessed correct and your total guesses is " + count );
break;
}
else if (guess > 100 || guess < 1) {
System.out.print("I see you cannot follow instructions. I said ");
count--;
}
else if (guess > num1) {
System.out.println("You have guessed too high. ");
}
else {
System.out.println("You have guessed too low.");
}
}
}
}
My problem is i am required to prompt the user at the point of "if the user quits or successfully guesses the correct number, prompt the user to see if they wish to play again". I am lost and not sure how to continue my while loop from the beginning after my breaks. Is there a way to end the break condition i have from (guess == num1 || guess ==0) and direct my program to start again at the while(true) statement?
Thanks
I will say search up continue;
Tips to help further:
The continue statement is used to bring the loop back to the start, try it instead of a break where you want the user to continue.
You need some sort of check if the user wants to continue, (try asking them to type in some specific int you check, p.s negative numbers are integers as well)
#Ahmed thinks you should continue, I would rather not break, or conditionally break.
Well there are multiple ways you could accomplish this, One would be to just to prompt the user with a "press q to quit" dialogue using the Scanner class where .next() returns the String when the user hits enter:
if(guess == num1 || guess == 0) {
if(guess == 0) {
System.out.println("Thanks for playing");
}else{
System.out.println("Congrats you've guessed correct and your total guesses is " + count );
}
System.out.println("would you like to play again [y/n]?");
if(scan.next().equals("y")){
num1 = generator.nextInt(100) + 1;
count=0;
}else{
break;
}
}
If thats what you mean. Hopefully I helped.
or maybe you can have it only quit at zero, if so just remove that second break and replace it with num1 = generator.nextInt(100) + 1; to set the new value to guess.

Why doesn't my Scanner work with 2 different if statements?

New to Java here. I made the following simple code that asks the user to choose between option 1 or 2. If the selected option is 1, then it should print "You said hi", which it works well, also if selected option is 2, it should prints "you said goodbye" which it doesn't, Am I missing something here? Maybe the If statement is wrong?
the Code:
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Please type 1 to say hi");
System.out.println("Please type 2 to say goodbye");
if (input.nextInt() == 1) {
System.out.println("You said hi");
} else if (input.nextInt() == 2) {
System.out.println("you said goodbye");
}
}
Every time you call nextInt() it stops to wait for an int. Here you want to compare a single int from the user with one or two. Save the int you get from the user. Like,
int v = input.nextInt();
if (v == 1) {
System.out.println("You said hi");
} else if (v == 2) {
System.out.println("you said goodbye");
}
Every time you call nextInt() on your scanner, input is being consumed. So in your case, when the else if condition is checked, the next input is consumed, not the previous one compared. You need to cache your scanner's state:
int answer = input.nextInt();
if (answer == 1) {
System.out.println("You said hi");
} else if (answer == 2) {
System.out.println("you said goodbye")
}
For your specific case, converting to a switch statement would be another option, which evaluates its operand only once:
switch (input.nextInt()) {
case 1:
System.out.println("You said hi");
break;
case 2:
System.out.println("you said goodbye")
break;
}
Every call to input.nextInt() will wait for the new key from input(here it is the user input).
the input.nextInt() == 1 will wait for the user input.
If it is validates to true, the thread will successfully execute System.out.println("You said hi").
Else if it validates to false, it will execute the condition in the input.nextInt() ==2 where the thread will keep waiting for the next input from the user because of the input.nextInt().
If you wish to get input from user only once, execute input.nextInt() only once and store it in a variable and run cases against it. Like,
// input from user
int selection = input.getInt();
if (selection == 1) {
System.out.println("the user entered 1");
}
else if (selection == 2) {
System.out.println("the user entered 2");
}
Please get input first then check it. (Don't get input in condition statement).
Your edited code is as follows:
Added one line (int selectedOption = input.nextInt())
edit condition statement (selectedOption == 1 and selectedOption == 2)
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Please type 1 to say hi");
System.out.println("Please type 2 to say goodbye");
//Get input
int selectedOption = input.nextInt() ;
//Check
if (selectedOption == 1) {
System.out.println("You said hi");
} else if (selectedOption == 2) {
System.out.println("you said goodbye");
}
}

While loop NoSuchElementException integer input java

I'm having some trouble with a menu program I am writing for my java class. After one program is run, when the program goes to do a second loop it throws a NoSuchElementException on the line where it is supposed to take the user's input for the next program they want to run. I'm assuming it has something to do with the scanner getting messed up but I can't find the issue. Anyone have any ideas?
public static void main(String[] args) {
Scanner console = new Scanner(System.in);
String pin;
int selection = 0;
boolean valid = false;
do {
System.out.print("Please enter the password: ");
pin = console.nextLine();
valid = checkPassword(pin);
} while (!valid);
while (selection != 4 && valid == true) {
System.out.printf("%nPlease select a number from the menu below %n1: Wage "
+ "Calculator 2: Tip Calculator 3: Grocery Discount 4: Exit %n");
selection = console.nextInt();
if (selection == 1) {
calc_wages();
} else if (selection == 2) {
calc_tip();
} else if (selection == 3) {
System.out.print("We haven't gotten this far yet");
} else if (selection == 4){
System.out.print("Thank you for using the program.");
break;
} else {
System.out.print("There is no option for what you entered. Try again");
}
selection = 0;
}
}//main
Your code so far is fine.
From what you're saying the problem starts after the user makes a selection.
In calc_wages() and/or calc_tip() it's possible that you use another Scanner object to get the user's input.
This is a source of problems.
Declare 1 Scanner object at the class level and use it throughout you code and close it only when it is no longer needed.

My while loop won't stop with a break? [duplicate]

This question already has an answer here:
How to use java.util.Scanner to correctly read user input from System.in and act on it?
(1 answer)
Closed 5 years ago.
if (sum < 6) {
System.out.println("You win");
System.out.println();
// Does the user want to retry?
System.out.print("Would you like to retry?(Y or N) : ");
String retry = input.nextLine();
while (true) {
// If they say y or Y, roll again
if (("y".equals(retry)) || ("Y".equals(retry))) {
roll();
// Check for anything other than y and Y
} else if (("n".equals(retry)) || ("N".equals(retry))) {
System.out.println("Closing");
break;
} else if (!("y".equals(retry)) || !("Y".equals(retry))) {
System.out.print("Invalid input. Would you like to retry?(Y or N) : ");
retry = input.nextLine();
System.out.println();
}
}
} else if (sum > 6) {
System.out.println("You lose");
System.out.println();
System.out.print("Would you like to retry?(Y or N) : ");
String retry = input.nextLine();
while (true) {
if (("y".equals(retry)) || ("Y".equals(retry))) {
roll();
} else if (("n".equals(retry)) || ("N".equals(retry))) {
System.out.println("Closing");
break;
} else if (!("y".equals(retry)) || !("Y".equals(retry))) {
System.out.print("Invalid input. Would you like to retry?(Y or N) : ");
retry = input.nextLine();
System.out.println();
}
}
}
I'm trying to make a dice game where the game will keep rolling the dices when the user inputs "y" or "Y". I also want it to stop the game and say "Closing" when the user inputs "n" or "N".
The issue is, when the user inputs "n" or "N", it will print out "Closing" but the loop doesn't stop and the game will roll the dices again. How to I make my while() loop stop when the user inputs "n" or "N"?
Here's the output when the user chooses to stop the game ("n" or "N") : Would
you like to retry?(Y or N) : n
Closing
Rolling...
You rolled : 1 & 4
Sum = 5
You win
I'm sorry for such basic question, I am new to programming.
Move the line String retry = input.nextLine(); into the while loop (in both if branches). Currently you read in one input and then compare that non-changing input over and over again.

Infinite looping; do not understand how

In the code below, when I input anything other than an integer value the code does not ask for my input again and just loops the string outputs infinitely. A little help...
int choice = 0;
while(choice == 0)
{
try
{
System.out.println("Start by typing the choice number from above and hitting enter: ");
choice = input.nextInt();
}
catch(Exception e)
{
}
if ((choice == 1) || (choice == 2) || (choice == 3))
{
break;
}
else
{
System.out.println("Invalid choice number. Please carefully type correct option.");
choice = 0;
}
}
When you input a non-integer it will not be consumed. You need to scan past it. This can be done by, for example, adding a input.nextLine() statement to your catch block. This will consume the invalid input and allow your program to read new data.
This will solve your problem:
catch(Exception e)
{
input.nextLine(); // Consume the invalid line
System.out.println("Invalid choice number. Please carefully type correct option.");
}
You could also read the line as a string and try to parse it as a number using Scanner.nextLine and Integer.parseInt, but I prefer using nextInt for integers. It makes the purpose of the code more clear (in my opinion).
When nextInt is used and the next input is not an int, it will throw an exception but not consume the data, i.e. the next call will return immediately because the data is still present.
You can fix this by calling the skip method with a pattern like [^0-9]* to skip all invalid input. Then an input like "aaa3" would work. If you want to ignore everything, use .* as pattern.
The trouble is that you are not consuming the remaining data in the stream. I solved it with the following code, although you will want to document you code better before you use it in a program:
int choice = 0;
while(choice == 0)
{
try
{
System.out.print("Start by typing the choice number from above and hitting enter: ");
choice = input.nextInt();
}
catch(Exception e)
{
input.next();
System.out.println("Invalid choice number. Please carefully type correct option.");
}
if ((choice == 1) || (choice == 2) || (choice == 3))
{
break;
}
choice = 0;
}
You can simplify and reduce your code as follows:
int choice;
System.out.println("Start by typing the choice number from above and hitting enter: ");
while(true)
{
try {
choice = input.nextInt();
if ((choice == 1) || (choice == 2) || (choice == 3))
break;
} catch(InputMismatchException e) { // handle only the specific exception
input.nextLine(); // clear the input
}
System.out.println("Invalid choice number. Please carefully type correct option.");
}
Are you using Scanner(system.in); from the import java.util.Scanner; package?
Try adding input.nextLine(); in the catch to clear the value to stop the infinite loop.
public static void main(String[] args) {
int choice = 0;
Scanner input = new Scanner(System.in);
while(choice == 0)
{
try
{
System.out.println("Start by typing the choice number from above and hitting enter: ");
choice = input.nextInt();
}
catch(Exception e)
{
input.nextLine();
System.out.println("Invalid choice number. Please carefully type correct option.");
}
if ((choice == 1) || (choice == 2) || (choice == 3))
{
break;
}
else
{
System.out.println("Invalid choice number. Please carefully type correct option.");
choice = 0;
}
}
}
Looks like in the line choice = input.nextInt();
choice value is always 0. Print choice soon after that.
Also for non integer value add a condition to break from the loop.

Categories

Resources