Prompt to continue while loop conflict - java

What seems fairly simple has got me completely confused. I ask the user for some inputs at the beginning of a while loop to be able to execute a program inside the loop. After the program is executed, I want to prompt the user at the end of the loop to restart or end the loop.
I am trying to make the loop ask only the LAST question after it has completed the program within it. Then, if the user has answered "yes", the loop will restart. Any other answer will result in ending the loop.
Here is my code
String rerun = null;
boolean run = true;
int x;
int y;
while (run = true)
{
// first question
x = keyboard.nextInt();
y = keyboard.nextInt();
// run program with x and y
// second question (ask to continue)
rerun = keyboard.nextLine();
if (rerun.equalsIgnoreCase("yes"))
{
continue;
}
else
{
run = false;
//break; stops the loop without answering the second question
}
}
Sample input/output:
Enter height and width of the house you want me to draw: 4 4
Program runs...
Bob, do you want me to draw another house for you (yes to continue)?
Enter height and width of the house you want me to draw (must be even numbers):
Why is it asking me the height and width again even though I have conditions at the end, prohibiting the loop to restart before I prompt it to continue?
Thank you!

Try this.
I haven't changed your code much, but I've printed a prompt on the screen before asking for a user input and printed the user input on the screen before restarting the loop. You could also do a try and catch block as below and see where the exception occurs. Also this would help in cause if a user enters a String instead of int for x or y.
import java.util.Scanner;
public class Test {
public static void main(String args[]) {
String rerun = null;
boolean run = true;
Scanner keyboard = new Scanner(System.in);
while (run == true) {
int x = 0;
int y = 0;
String val = "";
System.out.print("Enter x int : ");
try {
x = keyboard.nextInt();
}
catch (Exception ex) {
System.out.println("Error at x : " + ex.getMessage());
}
System.out.print("Enter x int : ");
try {
y = keyboard.nextInt();
}
catch (Exception ex) {
System.out.println("Error at y : " + ex.getMessage());
}
System.out.print("Enter string : ");
try {
val = keyboard.nextLine();
}
catch (Exception ex) {
System.out.println("Error at string: " + ex.getMessage());
}
System.out.println("x : " + x + ", y : " + y + ", val : " + val);
}
}
}

The problem is that after you use the nextInt() method the 'end of line' character is still in the input buffer. You must manually flush the buffer by calling nextLine(). I have modified your code below to show how you can fix this.
// first question
x = keyboard.nextInt();
y = keyboard.nextInt();
// run program with x and y
//Flush Input Buffer
keyboard.nextLine();
// second question (ask to continue)
rerun = keyboard.nextLine();

From your question it looks as though you want the loop to run at least once before the test. If that's the case then a do while loop is probably more appropriate than a while loop.
A do while loop looks something like:
do {
int x = keyboard.getInt();
int y = keyboard.getInt();
// process
System.out.println("Do you want to continue?");
} while (keyboard.nextLine().equalsIgnoreCase("yes"));
That seems to me to capture your intent better than the while loop of your original code and avoids having a keepRunning boolean (which I find confusing to read).
If you find the while statement confusing, rather than going back to a boolean variable, you can split the test into a separate method:
do {
...
} while (shouldRepeat());
private boolean shouldRepeat() {
System.out.println("Do you wish to continue?");
String answer = keyboard.nextLine();
return answer.equalsIgnoreCase("yes");
}
In my view that is still a clearer and less fragile solution than having a flag that is set.

Related

What is wrong with this java while loop?

New to Java and learning how to use While loops and random generator. This prints a multiplication question. Every time the user answers a question wrong, it should print the same question. Instead, it exits the program. What should I do?
while (true) {
Random multiply = new Random();
int num1 = multiply.nextInt(15);
int num2 = multiply.nextInt(15);
int output = num1 * num2;
System.out.println("What is the answer to " + num1 + " * " + num2);
Scanner input = new Scanner(System.in);
int answer = input.nextInt();
if (answer == output) {
if (answer != -1)
System.out.println("Very good!");
} else {
System.out.println("That is incorrect, please try again.");
}
}
If you want to repeat the same question when the user gets the answer wrong, you should use another while inside your main loop.
This inner loop continues to ask as long as you give a wrong answer.
I also replaced nextInt with nextLine, which reads in a whole line of text. This consumes the "Enter" key and is a safer approach at reading from the console. Since the result is now a String you need to use Integer.parseInt to convert it to an int. This throws an exception if you enter anything but a whole number so I wrapped it into a try-catch block.
If you want, you can add an additional check for validating user input. So in case the user wants to stop playing they only need to input "exit" and the whole outer loop will exit.
boolean running = true; // This flag tracks if the program should be running.
while (running) {
Random multiply = new Random();
int num1 = multiply.nextInt(15);
int num2 = multiply.nextInt(15);
int output = num1 * num2;
boolean isCorrect = false; // This flag tracks, if the answer is correct
while (!isCorrect) {
System.out.println("What is the answer to " + num1 + " * " + num2);
Scanner input = new Scanner(System.in);
try {
String userInput = input.nextLine(); // Better use nextLine to consume the "Enter" key.
// If the user wants to stop
if (userInput.equals("exit")) {
running = false; // Don't run program any more
break;
}
int answer = Integer.parseInt(userInput);
if (answer == output) {
if (answer != -1) {
System.out.println("Very good!");
isCorrect = true; // Set the flag to true, to break out of the inner loop
}
} else {
System.out.println("That is incorrect, please try again.");
}
}
catch(NumberFormatException e) {
System.out.println("Please enter only whole numbers");
}
}
}
Avoid while true. Declare a variable to true, pass the variable to the condiciĆ³n loop and set it to false when the answer is incorrect. You can use break too, but is easier to read the code when you use a exit condition in the while. Also read more about loops https://docs.oracle.com/javase/tutorial/java/nutsandbolts/while.html

Java Integer.parseInt() breaks program

I have a question to do in my Java class, and it asks me to write a program that takes in n numbers from the user and outputs the average of them. I know I could do it a much simpler way, just by asking the user to enter the amount of values (s)he needs to enter at the beginning, but I want to create the program so the user doesn't necessarily have to know the number of values at the beginning.
So for this, I create an array of 100 length (which hopefully covers the amount the user needs to enter) inside a for loop (rendering that 100 length array null after the loop, so the program doesn't become too memory heavy) and running a counter trough each iteration. Once the user enters stop, the loop ends, and the values entered into the 100 length array gets transferred to an array the size of the count.
Here is the code:
import java.util.*;
import java.lang.*;
public class main
{
public static void main(String args[])
{
Scanner input = new Scanner(System.in);
//Question 1
System.out.println("Enter your numbers. (Enter 'Stop' when you're done)");
int temp = 0;
String uInput = "";
char stopper;
int count = 0;
double total = 0;
int a = 0;
boolean inStop = true;
for (boolean stop = false; stop != true;)
{
int array [] = new int [100];
if (inStop == true)
{
System.out.println("point 5");
System.out.print("Input: ");
uInput = input.nextLine(); //reads user input
}
try //empty input repeater
{
System.out.println("point 1");
try //dealing with letters in string instead of numbers
{
System.out.println("point 2");
temp = Integer.parseInt(uInput); //converts string to int
array[count] = temp;
count++;
System.out.println(inStop);
if (inStop == false) //executes when stop has been reached
{
System.out.println("point 3");
int numberArray [] = new int [count]; //fills final array
for (int i = 0; i < count; i++)
{
numberArray[i] = array[i];
}
for (a = 0; a < numberArray.length; a++)
{
total = total + numberArray[a];
}
total = total / a;
stop = true; //ends parent loop
}
}
catch (NumberFormatException e) //catches letters in string and checks for stop
{
System.out.println("point 4");
stopper = uInput.charAt(0);
stopper = Character.toUpperCase(stopper);
if (stopper == 'S')
{
inStop = false;
System.out.println("point 6");
}
}
}
catch (StringIndexOutOfBoundsException e)
{
}
}
System.out.println("The average of the values entered is: " + total + ".");
}
}
The problem is, as you can see there are numerous numbered printouts that indicate (to me) where the program is at the moment. All runs fine, except for point 3. Point 3 for some reason doesn't execute whatsoever. No matter what I do. Now, the problem lies on line 34, temp = Integer.valueOf(uInput); //converts string to int
If I put in a print function directly after that line, that position doesn't print onto the screen. I believe there are no syntax or logic errors with that part, and so does my lecturer, however the code still doesn't execute and the program loops infinitely afterwards. Something is breaking either temp or uInput in that line and we cannot figure out what. I have compiled and ran the code through a different compiler to what I initially used and even tried in the Command Prompt with the same results (so it is not the IDE causing the issue).
Any insight we may have missed would be appreciated. Thanks.
p.s.: don't knock my lecturer, he didn't write the code, and it isn't that easily readable. He could easily know what the problem is, if not for any error in my explanations or his interpretations of how my program is meant to run.
I think that the reason you are having a problem identifying the issue is because of your code structure.
You have mixed the logic for informing the use, with the logic for reading the inputs, and calculating.
If your main method only deal with informing the user, and relies on another method to calculate the average,and another to read the user's input everything will be easier to read, follow and see that you are parsing "stop" as an int.
public static void main(String[] args) {
System.out.println("instructions");
int[] all = readUserInputs();
double ave = calculateAverage(all);
System.out.println("message " + ave);
}
private static double calculateAverage(int[] numbers) {
// I will leave it to you to fill this out
return yourValue;
}
private static String readUserInputs() {
Scanner input;// as above
int[] values; // is an array best? What about a List?
for (int i = 0; ; i++) {
String line = input.nextLine();
if ("stop".equals(line) {
break;
}
//try to parse and put into array/list
}
return values;
}
Hopefully you will find this easier to read and work with,I have left a few gaps for you to fill in.

Java Scanner try catch multiple data types

First of all thanks for everything you, guys are doing here on stack overflow. It helped me a lot many times!
My problem today is a little issue with try/catch instruction using along with Scanner. Take a look at my method for adding products to a recipe:
public static void addProducts(List<Product> product, Scanner sc)
{
if (run == true)
{
Maths calc = new Maths();
//Some instructions in Polish, not needed here :)
while (true)
{
String name = null;
double quantity = 0;
double pricePerUnit = 0;
try
{
name = sc.nextLine();
if (name.equals("0") || name.equals("exit"))
{
Logic.run = false;
break;
}
quantity = sc.nextDouble();
sc.nextLine();
pricePerUnit = sc.nextDouble();
sc.nextLine();
product.add(new Product(product.size() + 1, name, calc.round(quantity, 2), calc.round(pricePerUnit, 2)));
System.out.println("Product added: " + "\n" + product.get(product.size() - 1));
} catch (InputMismatchException e)
{
System.out.println("Error! Please repeat your last input.");
}
}
double num = 0;
for (Product p : product)
{
num += p.getPrice();
}
Maths.setTotalPrice(num);
System.out.println("Total: " + num);
} else
{
System.out.println("You have already added products to the recipe!");
}
}
As you can see im reading String, double and double in the try/catch instruction. For example when adding "potatoes" to the recipe I accidentaly write "horse" where quantity should be I get a product named "horse" instead of "potatoes". Is that clear? I have a yellow duck right here but its easier to explain in my native language than it is in English :)
If there is anything unclear I will do my best to explaing, thanks!
When you do:
quantity = sc.nextDouble();
sc.nextLine();
you're throwing away any extra input, without acknowledgement. If you want to restrict user to only enter a number and nothing else on a line, use:
quantity = Double.parseDouble(sc.nextLine()); // maybe add .trim()
If you leave your code unchanged, remember that when InputMismatchException is thrown, the Scanner is still sitting on (at beginning of) the bad input, so you need to discard that:
} catch (InputMismatchException e)
{
System.out.println("Error! Please repeat your last input.");
sc.nextLine(); // discard bad input
}
Of course, your code will loop around and prompt for all 3 inputs, so error message is a bit misleading.

Having an incedibly tough time with a loop

I've copied part of the instructions below, and I can code pretty much every part on its own, but getting the control flow together is giving me massive doubts about my ability.
One of my biggest problems is the int gameChanger. Im supposed to immediately verify if it is a integer or not, and loop back if its not. But then Im also supposed to check to see if thebuser ever types "exit". But the input variable for my scanner instance is an integer... So Im stumped. I can use a try catch to check the missmatchexception once the input is being read in, but that doesnt solve the exit issue nor am I able to come up with solid logic to get the try catch to loop back if it indeed isnt an integer. Im thinking a do while loop but I havent gotten it to work.
Instructions:
You can whether the input is a number before attempting to consume it.
int num;
while (true) {
if (scanner.hasNextInt()) {
num = scanner.nextInt();
break;
} else {
// read whatever is there instead.
String line = scanner.nextLine();
if (line.equals("exit"))
System.exit(0);
System.out.println("Please enter a number");
}
}
System.out.println("Number entered " + num);
This gets the job done. Try it out.
import java.util.Scanner;
public class MyCode
{
public static void main(String[] args)
{
String gameInput = ".";
int gameNumber = 0;
boolean inputLoop = true;
Scanner input = new Scanner(System.in);
while(inputLoop == true)
{
try
{
System.out.print("Please enter a valid game number: ");
gameInput = input.next();
if(gameInput.equals("exit"))
{
System.out.println("Program will now end. Goodbye.");
inputLoop = false;
input.close();
}
gameNumber = Integer.parseInt(gameInput);
if(gameNumber >= 20001 && gameNumber <= 21230)
{
System.out.println("You have inputted a valid game number.");
inputLoop = false;
input.close();
}
}
catch(NumberFormatException e)
{
if(!gameInput.equals("exit"))
{
System.err.println("Invalid game number. Please try again.");
}
}
}
}
}

Infinite Looping Caused by Exception Handling

What I want this code to do is handle the exception, and then simply repeat. What it does instead, unfortunately, is loop infinitely... I can't figure out why.
It never asks for the input to be re-entered, seemingly setting it for good the first time. However, this ONLY happens when an exception is thrown; if the user enters an invalid integer, there is no problem at all with the looping process.
I'm relatively new to all this, so I was hoping to get a second opinion before just forcing the loop to exit when an exception is caught.
Scanner scan = new Scanner(System.in);
// Variables associated with the clock:
private int h; // h = Hours
private int m; // m = Minutes
private int s; // s = Seconds
public boolean userPrompt() {
String answer = "";
// Loops while until a clock is generated and selected
while (! answer.equals("y")) {
System.out.println("What time is it?");
try {
// Asking for the time, one variable at a time.
System.out.print("H >> ");
h = scan.nextInt();
System.out.print("M >> ");
m = scan.nextInt();
System.out.print("S >> ");
s = scan.nextInt();
// Testing for the validity of the clock's time:
if ((h < 24 && h >= 0) && (m < 60 && m >= 0) && (s < 60 && s >= 0)) {
// Displaying the formatted clock's time:
System.out.printf("Clock { %02d:%02d:%02d }\n", h, m, s);
System.out.println("Save clock generated?");
System.out.print("Answer (y/n): ");
answer = scan.next();
}
} catch (InputMismatchException iox) {
// Here lies the issue, I think...
System.out.println("ERROR: " +iox);
}
}
// A safeguard for the next method in the program
return answer.equals("y");
}
use finally after catch block and put the following two statements in it like this :
try {
} catch(InputMismatchException iox) {
} finally {
System.out.print("Answer (y/n): ");
answer = scan.next();
}
Note : When exception occurs before System.out.print("Answer (y/n): "); and
answer = scan.next(); statements,these two statements are not executed.But the statements within the finally block executes regardless of what happens within the try block.So,if you use the two statements in finally block these will always be executed infinite looping won't happen.

Categories

Resources