Why is my exception handling causing an infinite loop? - java

I'm writing a method that will return an integer value. In the method I am prompting the user for the integer via console through the scanner class.
Because I am using the scanner method "scan.nextInt()", I am also checking for "InputMismatchException" error. I have placed the exception handling in a loop so that if the exception is caught the user is notified and the loop is reiterated. This will require the user to keep entering values until only an integer value has been entered.
However, my issue is after the first time it checks for the error, when it loops back, something is happening and the user is not prompted to enter a new value and the exception is thrown again. This of course results in an infinite loop.
I've researched and found a few cases related to the issue and I've tried performing relevant fixes but nothing I do seems to work and I don't understand what exactly is happening. Is the try block being skipped? Is there something wrong with my notation for the try block?
public static int inputCheck() {
int check=0;
int money = 0;
while (check==0) {
boolean error = false;
System.out.println("Please enter the amount of money your player has.");
while (true) {
try {
money = scan.nextInt();
}catch (InputMismatchException wrongInput) {
System.out.println("Error. Please enter an integer value." + wrongInput);
error = true;
}
break;
}
if (error==false)
check++;
}
return money;
}
EDIT Code has been edited and the "error" boolean value has been adjusted

The problem is in your catch when you set error equal to true. Once error is set to true, your loop is constructed in a way that has no way of exiting because error is never set to false therefore check is never incremented. I would re-structure this this loop system in general, there are much better approaches to handling this.

Try with this:
public static int inputCheck() {
int check = 0;
int money = 0;
while (check == 0) {
boolean error = false;
System.out.println("Please enter the amount of money your player has.");
try {
money = Integer.parseInt(scan.next());
} catch (Exception e) {
System.out.println("Error. Please enter an integer value." + e);
error = true;
}
if (error == false) {
check++;
}
}
return money;
}

while(true) is never false, so the loop never terminates if it doesn't hit the break statement

Related

java: loop with switch only works sometimes

I'm really scratching my heard on this one. I'm new at java, and I'm having the strangest thing happen.
It's homework and I'm taking it one step at a time. My issue is the loop just keeps going and stops asking for input, just keeps looping until it terminates. My comments are largely for myself. I tried to extract what was causing my problem and post it here.
Look at the "hatColor" switch, you'll notice the way I'm making sure the user enter only from the options I have allotted. Should I be using a exception handler or something?
Anyway, in short, the problem is that if I enter something with spaces, the loop skips asking for my next input. Like, if I entered "y y y y y " to the scanner when first prompted, the program will terminate and not give me the chance to enter something else.
Please, anyone that understands this, I would really appreciate your help.
import java.util.Scanner;
public class Testing
{
static String hatColor;
public static void main(String[] args) {
gameStart();
}
public static void gameStart()
{
Scanner userInput = new Scanner(System.in);
boolean keepLooping = true;
int loopCounter = 0;
System.out.println("The game begins. You must choose between 3 different colored hats."
+ " You can type white, black, or gray.");
while (keepLooping == true)
{
hatColor = userInput.next();
switch(hatColor)
{
case "white":
System.out.println("You have chosen the path of well intentioned decisions.");
walletDrop();
//the two items below are only there in case the wallet drop somehow completes without calling another method
keepLooping = false; // stops the while loop from looping again.
break; // breaks out of the switch
case "gray":
System.out.println("You have chosen the path of free will.");
walletDrop();
keepLooping = false;
break;
case "black" :
System.out.println("You have chosen the path of personal gain.");
walletDrop();
keepLooping = false;
break;
default : //we could just copy this default chunk for later switch statements
if (loopCounter >= 3)//end program on them
{
System.exit(0);
}
System.out.println("You didn't enter a usable answer. Try again");
loopCounter++;
if (loopCounter == 3)
{
System.out.println("This program will self destruct if you enter another invalid response.");
}
}//end of switch
}//end of while
}//end of game start method
public static void walletDrop()
{
System.out.println("wallet drop successful");
}
}
So I have actually solved this right after posting. In case someone else needs to look here for help:
The issue I was experiencing was due to using the scanner method
variableToAssign = scannerName.next();
instead of
variableToAssign = scannerName.nextLine();

Java Battleship: invalid input is still sent to next method

I wrote a piece of code to implement a Battleship game.
One of its methods (pickRow) is meant to let the user pick a row in the playing field (5x5) to fire in. This method checks checks whether the user input is within the boundaries of the playing board (as mentioned 5x5) and if the user input is an integer (see try-catch statement).
However, the program gives an error as the user input is for example 444 (=invalid input). Although forcing the user to provide another number, the 444 is still transferred on to the next methods (playerAttempt & adaptBoardAfterAttempt), raising an ArrayIndexOutOfBoundsException.
How can I fix the code so that the invalid user input is no longer transferred to subsequent methods? For my code, see below.
Thanks,
Sander
public static int pickRow(int row) {
//method to let the user pick a row
//
Scanner rowInput = new Scanner(System.in);
try { //checks if user input is an integer by using try-catch statement
System.out.print("Pick a row (1-5): ");
row = rowInput.nextInt();
if (!isWithinBoundaries(row)) { //checks if user input is within boundaries of the playing board
System.out.println("That's outside the sea. Please provide a number from 1 to 5.");
pickRow(row); //asks for new user input because user input is outside boundaries of the playing board
} else {
row = row - 1; //adjusts the value of row to correct for programming indices
}
} catch (java.util.InputMismatchException e) {
System.out.println("Sorry, invalid input. Please provide a number from 1 to 5.");
pickRow(row); //asks for new user input because input is not an integer
}
return row;
}
public static int pickColumn (int column) {
//method to let the user pick a column
//
Scanner columnInput = new Scanner(System.in);
try { //checks if user input is an integer by using try-catch statement
System.out.print("Pick a column (1-5): ");
column = columnInput.nextInt();
if (!isWithinBoundaries(column)) { //checks if user input is within boundaries of the playing board
System.out.println("That's outside the sea. Please provide a number from 1 to 5.");
pickColumn(column); //asks for new user input because user input is outside boundaries of the playing board
} else {
column = column - 1; //adjusts the value of column because java starts counting at 0, not 1
}
} catch (java.util.InputMismatchException e) {
System.out.println("Sorry, invalid input. Please provide a number from 1 to 5.");
pickColumn(column); //asks for new user input because input is not an integer
}
return column;
}
public static void playerAttempt(int[] playerAttempt) {
//method that incorporates player's picks of row and column into an attempt
playerAttempt[0] = pickRow(row);
playerAttempt[1] = pickColumn(column);
}
public static void adaptBoardAfterAttempt (int[] playerAttempt, int[][] ships, int[][] board) {
//adapts the playing board after a player attempt to indicate a hit (X) or a miss (0)
if (isHit(ships,playerAttempt)) {
board[playerAttempt[0]][playerAttempt[1]]=2;
} else {
board[playerAttempt[0]][playerAttempt[1]]=1;
}
}
Here's what worked for me (my comments start with ">>"):
public static int pickRow() {
//method to let the user pick a row
Scanner rowInput = new Scanner(System.in);
String response;
int row;
while (true) //>> loop is infinite as long as input is invalid. As soon as it's valid, method returns, exiting the loop.
{
//checks if user input is an integer by using try-catch statement
System.out.print("Pick a row (1-5): ");
response = rowInput.nextLine();
try {
row = Integer.valueOf(response);
} catch (NumberFormatException e)
{
System.out.println("Sorry, invalid input. Please provide a number from 1 to 5.");
continue;
}
if (!isWithinBoundaries(row))
{ //checks if user input is within boundaries of the playing board
System.out.println("That's outside the sea. Please provide a number from 1 to 5.");
} else
{
row = row - 1; //adjusts the value of row to correct for programming indices
return row; //>> row is valid, so return it
}
}
}
Here's what I changed:
I removed your argument row. It doesn't need to be an argument passed to the method, since your Scanner retrieves the value for row. Instead, I declared it as a method-level variable.
I added a String variable called response. I changed your code to retrieve this as the user's input, rather than row. (i.e., your Scanner uses nextLine() now rather than nextInt().
I placed the rest of the code in an infinite while loop and deleted your recursive pickRow() calls. This way, the method just keeps asking for input until it's finally a valid response, at which point the method returns the row number. In any other instance, the response is not valid and the loop continues.
I rearranged your exception handling to catch a NumberFormatException when I try to convert response to an integer (to assign to row). If an exception is thrown, it prints your error message and the loop continues again.
In short, when the method is called, the program asks for 1 - 5. If it's too big or small, isWithinBoundries catches it, and the program asks again. If it's not a number, the catch block catches it, and the program asks again. If it's a valid value, the method does your -1 procedure and returns the row.
I hope this helps!

Java help regarding looping (do loops)

I'm trying to make a very basic game where you guess a number between 1-1000 using a do loop. Everything works, except when I finally make the correct guess, I am still prompted to make another guess, and when I enter the same correct guess again, the program terminates like it's suppose to.
Why do I have to make that extra guess to finally get my program to work? Am I looping around an extra time? Also, if I make a correct guess (the compiler will say I am correct then still prompt me), then a wrong guess (the compiler will tell me I'm wrong), then the correct guess again, the program will only terminate after I make the correct guess a second time.
The second do loop at the bottom is what I put in my main method. Everything above is in a method I wrote called play.
public static boolean play()
{
boolean c;
int n = 0;
do {
String input = JOptionPane.showInputDialog("Enter a number between 1-1000");
n = Integer.parseInt(input);
if (n == guess)
{
System.out.println("Correct");
c = true;
}
else if (n < guess)
{
System.out.println("Not Right");
c = false;
}
else
{
System.out.println("Not Right");
c = false;
}
guess++;
} while (c == false);
return c;
}
In main method:
do {
game1.play();
} while (game1.play() != true);
This loop runs the play method twice in each iteration of the loop :
do {
game1.play(); // first call
} while (game1.play()!=true); // second call
You are not testing the value returned by the first call, so even if it returns true, you would still call game1.play() again, which will display "Enter a number between 1-1000" again.
Replace it with:
boolean done = false;
do {
done = game1.play();
} while (!done);
This would only call play() one time in each iteration of the loop.
That said, I'm not sure why you need the outer loop.
You can just replace in with one call to game1.play(), since game1.play() will loop until the correct number is entered.

Issue with do-while loop

Please note that I while I am comfortable with Java, I am not exceptionally gifted nor do I know all the jargon, so please explain your answers with very little coder jargon and as much normal English, or explain what the jargon means after you use it. Also, this is my first time with Stackoverflow, so let me know if this was a decent question and give me some pointers.
I am taking an AP Computer Science class at my high school. We use Java. We were recently taught do-while loops and I just completed the "lab" that uses do-while loops, however, there is an issue.
Firstly, let me explain the lab. The program generates a random integer between 1-10 which the user must guess (guess is stored as an int using a scanner), there are a few integer values which track number of guesses, how many guesses were greater than the computer integer, and how many were too low. When you look at my code, you will notice that I have a System.out.println(compGen);//compGen is the computer generated int. The purpose was to test the code.
The issue is in the if-statement that compares userGen (user guess) and compGen.
if(userGen==compGen)
{
//do a lot of stuff
}
In this if-statement, it is not printing the correct SOPs that I have written IF the user guesses more than once. HOWEVER, I did not write this into the program, it seems to do it on its own. I used the SOP I mentioned early where the compGen int is printed, and I typed that in as my first guess and it worked perfectly. Everything in the if-statement block executed perfectly and printed everything correctly. However, when I did it as my second guess, third guess, or any guess that was not the first one, NOTHING was printed. See code below and run it. I don't believe this should make a difference, but the IDE that I use is Eclipse, hence the package statement. Please help.
package Chapter_3.Lab03_Chapter3;
import java.util.*;
public class Guess
{
public static void main(String[] args)
{
Scanner userInput = new Scanner(System.in);//Scanner
int compGen = (int)(Math.random()* 10 + 1);//compGen is computer number
System.out.println(compGen); //USED TO VERIFY FAILURE. VALUE WAS ENTERED TO TEST CODE
int guessTrack = 0;//tracks number of guesses
int tooHighTrack = 0;//CREATING INTS TO TRACK STUFF
int tooLowTrack = 0;
System.out.println("Welcome to the integer guessing game that everyoone loves!");//PROMPT
System.out.println("Please enter your guess for the integer. Remeber, it is between one and ten.");//GREETING
int userGen = userInput.nextInt();//USER GUESS
do
{
guessTrack++;//Increase guess value
if(userGen > compGen)//checks user value in relation to computer generated int
{
System.out.println("Try again! Your guess was too high!");//inform user of bad guess
userGen = userInput.nextInt();//new guess
tooHighTrack++;//if guess is too high, this int tracker increases
}
else if(userGen < compGen)//checks user value in relation to computer generated int
{
System.out.println("Try again! Your guess was too low!");//inform user of guess
userGen = userInput.nextInt();//new guess
tooLowTrack++;//increases if user guess is too low
}
else if(userGen==compGen)//if both values are equivalent, execute THIS IS THE PROBLEM STATEMENT!!
{
System.out.println("Great job! You guessed the right number!");//congratulate
if(guessTrack>1)
{
System.out.println("It took you: "+guessTrack+" guess to get the right answer.");//print guess tracked int
}
else
{
System.out.println("It took you: "+guessTrack+" guesses to get the right answer.");//print guess tracked int
}
System.out.println(tooHighTrack +" guesses were too high and "+ tooLowTrack+ " were too low.");//print how many guess were too big or too low
System.out.println("HELLO"); //Used to verify failure of code
userInput.close();//close scanner object
}
}
while (userGen != compGen);//condition to be ultimately checked
}
}
I haven't been able to figure out what is wrong. At one point I deleted the entire if-statement and re-typed it (I knew it wouldn't do anything, but I had to try). This issue makes no sense to me. There are no errors or anything that pop up, nothing pops up on the console which scares me a little. Thanks in advance.
First off, a lot of text you put here. Maybe try to minimize the problem next time as a suggestion ;) Otherwise everything is fine
To your problem. Let me minimize your code and then explain to you, what happens.
1. The Code
int val = scanner.nextInt();
do {
if (val < 5) {
// too low
val = scanner.nextInt();
} else if (val > 5) {
// too high
val = scanner.nextInt();
} else {
// correct
// THIS CODE DOESN'T RUN?!
}
} while (val != 5);
2. What does your code do?
You read your first number before your loop. That's fine. Then, you enter an if-elseif-else statement. Note, that once inside one of those blocks, the other blocks won't get executed. Now the problem is, that you read your next user inputs inside of the if-elseif! The program reads the next value and leaves the whole if-elseif-else. Your code does not execute, because the loop then ends before the next iteration, therefore the correct user input is not going through the if-elseif-else at all.
3. The solution
Remove all nextInt() reads and just have one as the first thing inside the loop:
int val;
do {
val = scanner.nextInt();
if (val < 5) {
// too low
} else if (val > 5) {
// too high
} else {
// correct
// THIS CODE RUNS NOW!
}
} while (val != 5);
Such things, structures that need to do something at least once before checking the loop condition, are usually done with do while loops rather than while loops
You are setting user input during the loop, and it is then checked afterwards. Try moving the body of the else if(userGen==compGen) block to after the loop like this:
public static void main(String[] args)
{
Scanner userInput = new Scanner(System.in);//Scanner
int compGen = (int)(Math.random()* 10 + 1);//compGen is computer number
System.out.println(compGen); //USED TO VERIFY FAILURE. VALUE WAS ENTERED TO TEST CODE
int guessTrack = 0;//tracks number of guesses
int tooHighTrack = 0;//CREATING INTS TO TRACK STUFF
int tooLowTrack = 0;
System.out.println("Welcome to the integer guessing game that everyoone loves!");//PROMPT
System.out.println("Please enter your guess for the integer. Remeber, it is between one and ten.");//GREETING
int userGen = userInput.nextInt();//USER GUESS
do
{
guessTrack++;//Increase guess value
if(userGen > compGen)//checks user value in relation to computer generated int
{
System.out.println("Try again! Your guess was too high!");//inform user of bad guess
userGen = userInput.nextInt();//new guess
tooHighTrack++;//if guess is too high, this int tracker increases
}
else if(userGen < compGen)//checks user value in relation to computer generated int
{
System.out.println("Try again! Your guess was too low!");//inform user of guess
userGen = userInput.nextInt();//new guess
tooLowTrack++;//increases if user guess is too low
}
}
while (userGen != compGen);//condition to be ultimately checked
//The numbers have matched since it exited the loop.
System.out.println("Great job! You guessed the right number!");//congratulate
if(guessTrack>1)
{
System.out.println("It took you: "+guessTrack+" guess to get the right answer.");//print guess tracked int
}
else
{
System.out.println("It took you: "+guessTrack+" guesses to get the right answer.");//print guess tracked int
}
System.out.println(tooHighTrack +" guesses were too high and "+ tooLowTrack+ " were too low.");//print how many guess were too big or too low
System.out.println("HELLO"); //Used to verify failure of code
userInput.close();//close scanner object
}
The while condition is checked as soon as the program reaches the end of the code inside the loop. So suppose they enter the wrong number; the program says it's too low or too high, and then asks for another number:
userGen = userInput.nextInt();//new guess
Now suppose this new number is the correct one. The program finishes your if statement, then gets to the end of the loop. Then, at that point, userGen is equal to compGen. So the while condition fails, and the program exits the loop immediately, without ever getting to the code that prints the results.
One way to solve it would be to move the logic for userGen == compGen, that prints the results, outside the loop--that is, after the end of the loop. That way, it will be executed whenever the loop is exited. Note that when you exit the loop, we know that userGen == compGen, because if it weren't, the loop would go back.
Let's say the computer generated number was 3, and you guess 5.
5>3, so the if(userGen > compGen) statement executes:
System.out.println("Try again! Your guess was too high!");//inform user of bad guess
userGen = userInput.nextInt();//new guess
tooHighTrack++;//if guess is too high, this int tracker increases
you print the message, get a new guess, then increment your counter... but when you get the new guess, say it was the correct answer 3, userGen is now equal to CompGen (both are 3) and now the
while condition is evaluated:
while (userGen != compGen)
this is now false because userGen == compGen (both are 3). Your code never gets a chance
to print the correct message because the loop exits before it can happen. hope that helps
Your userGen is not being checked after every user input.
The problem is that you have your check inside an else-if block, which will check the end of the while statement before it loops back through again.
If you change
else if(userGen==compGen)
to
if(userGen==compGen)
then because it is not apart of the if-else block, it will be checked after every input (before the while condition is checked)
Alternatively you could move your user-input to the start of the do-while block like so:
package Chapter_3.Lab03_Chapter3;
import java.util.*;
public class Guess
{
public static void main(String[] args)
{
Scanner userInput = new Scanner(System.in);//Scanner
int compGen = (int)(Math.random()* 10 + 1);//compGen is computer number
System.out.println(compGen); //USED TO VERIFY FAILURE. VALUE WAS ENTERED TO TEST CODE
int guessTrack = 0;//tracks number of guesses
int tooHighTrack = 0;//CREATING INTS TO TRACK STUFF
int tooLowTrack = 0;
System.out.println("Welcome to the integer guessing game that everyoone loves!");//PROMPT
System.out.println("Please enter your guess for the integer. Remeber, it is between one and ten.");//GREETING
int userGen = -1;//USER GUESS
do
{
userGen = userInput.nextInt();
guessTrack++;//Increase guess value
if(userGen > compGen)//checks user value in relation to computer generated int
{
System.out.println("Try again! Your guess was too high!");//inform user of bad guess
userGen = userInput.nextInt();//new guess
tooHighTrack++;//if guess is too high, this int tracker increases
}
else if(userGen < compGen)//checks user value in relation to computer generated int
{
System.out.println("Try again! Your guess was too low!");//inform user of guess
userGen = userInput.nextInt();//new guess
tooLowTrack++;//increases if user guess is too low
}
else if(userGen==compGen)//if both values are equivalent, execute THIS IS THE PROBLEM STATEMENT!!
{
System.out.println("Great job! You guessed the right number!");//congratulate
if(guessTrack>1)
{
System.out.println("It took you: "+guessTrack+" guess to get the right answer.");//print guess tracked int
}
else
{
System.out.println("It took you: "+guessTrack+" guesses to get the right answer.");//print guess tracked int
}
System.out.println(tooHighTrack +" guesses were too high and "+ tooLowTrack+ " were too low.");//print how many guess were too big or too low
System.out.println("HELLO"); //Used to verify failure of code
userInput.close();//close scanner object
}
}
while (userGen != compGen);//condition to be ultimately checked
}
}
This will cause your if-else block to be checked everytime a user inputs data before the conditions for the do-while are checked.

How to create a mutator method that adds together two numbers then displays a message

How do I create a mutator method that adds two numbers but if the added number that is entered is negative, it will display an error message and not change the first number. Suggestions please.
public void restock(int newStockQuantity)
{
if(newStockQuantity < 0)
{
stockQ = stockQ;
}
{
system.out.println("Error not negative numbers");
}
else
{
stockQ = stockQ + newStockQuantity;
}
}
Well, for one thing you don't need the
stockQ = stockQ;
statement - that doesn't do anything.
Next is the problem of having multiple blocks in the "if" statement. If you did want to keep the no-op assignment, you could change your method to:
public void restock(int newStockQuantity)
{
if(newStockQuantity < 0)
{
stockQ = stockQ;
System.out.println("Error not negative numbers");
}
else
{
stockQ = stockQ + newStockQuantity;
}
}
With the no-op assignment removed, it's just:
public void restock(int newStockQuantity)
{
if(newStockQuantity < 0)
{
System.out.println("Error not negative numbers");
}
else
{
stockQ = stockQ + newStockQuantity;
}
}
Note the change from "system" to "System" as well - Java is case-sensitive.
That should compile and work.
Personally I would suggest throwing an exception if the method has an invalid argument instead of printing out a message to the console, but obviously it depends on the situation.
If you don't understand my first comment about having multiple blocks for the if statement, then I'd suggest going back to a good introductory Java book, and look at the syntax of if statements. It's slightly unclear which point you were having trouble with.
IMHO the best approach is the exception. Another point is to output the offending value, so a user of the method knows what the error is about. It also reveals errors in your check ;). Third point is to check for invariants first, bailing out with an exception or some appliable return-statement.
public void restock(int newStockQuantity) {
if(newStockQuantity < 0) {
throw new IllegalArgumentException("new stock " + newStockQuantity " must not be negative");
}
if (newStockQuantity == 0)
{
// nothing necessary, probably worth another exception?
return;
}
stockQ = stockQ + newStockQuantity;
}

Categories