Do..While loop keeps repeating, Scanner issue - java

do {
System.out.println("Set the A param: ");
if(input.hasNextDouble() == true) {
A = input.nextDouble();
if(A == 0) {
System.out.println("Param A cannot be a 0!");
}
} else if(input.hasNextDouble() == false) {
System.out.println("Param A must be a number!");
}
} while(A == 0 || input.hasNextDouble() == false);
Hello, I'm really new in Java and I found an obstacle I can't resolve by myself.
Everything is okay until I enter some letter instead of number, then this do..while loop keeps repeating itself.
After some search I suppose this might be a problem with a Scanner buffer becouse I should clear it before every loop with input.nextLine() but I don't really know where in code should I put it.
Thanks for any help.

You only actually consume data from the scanner if input.hasNextDouble() is true.
Currently, if A == 0 and there are non-numeric data in the buffer then you'll indeed loop indefinitely.
You need to consume data from the buffer on all control paths. In particular, if there is something non-numeric in the buffer, then you need to consume and immediately discard it: input.next(); would be adequate.

Seems like you just want to get the value of A which should not be equal to 0 . Read comments
double A=0;
do {
System.out.println("Set the A param: ");
if(input.hasNextDouble() == true) { //check for valid value
A = input.nextDouble();
if(A == 0) {
System.out.println("Param A cannot be a 0!");
}
} else{ // no valid value found , print msg and jump over the previous input
input.nextLine();
System.out.println("Param A must be a number!");
}
} while(A == 0); // just check , if the desired value is received
// previously input.hasNextDouble() had no use cuz we already
// checked no double value found so will be false, don't use it

First, you should not write the opposing check in an else if. Just use else. And you shouldn't check == true, since the value is already a boolean.
Now, for you infinite loop problem, when hasNextDouble() is false, it means that the user entered something wrong (ignoring the potential end-of-stream issue). In that case you need to discard that bad input, which is best done by calling nextLine().
Java naming convention states that variables should start with lowercase letter, so A should be a.
Your code then becomes:
double a = 0;
do {
System.out.println("Set the A param: ");
if (input.hasNextDouble()) {
a = input.nextDouble();
if (a == 0) {
System.out.println("Param A cannot be a 0!");
}
} else {
input.nextLine(); // discard bad input
System.out.println("Param A must be a number!");
}
} while (a == 0);

Thank you for both answers, after first I wrote this:
do
{
System.out.println("Podaj wartość parametru A: ");
if(input.hasNextDouble() == true)
{
A = input.nextDouble();
if(A == 0)
{
System.out.println("Parametr A nie może być zerem!");
}
}
else if(input.hasNextDouble() == false)
{
System.out.println("Parametr A musi być liczbą!");
input.nextLine();
A = 0;
}
} while(A == 0);
And it worked but thanks to the second answer now I know how to do it better. :)
Thanks both of you once again.

Related

Checking if a user input that should be an int is a string

I'm trying to make this Sentinel program more robust by continuing it even when incorrect user inputs are received. I've gotten it to work if the user input is a different int, but if it is a string, or anything else really, the program crashes.
My current code attempt is this:
} else if (userInt != 1 && userInt != 2 && userInt != 3 && userInt != 4 && userInt != 5 && userInt !=6
|| userInt instanceof String) {
The first part of this code works fine at checking if the user input is a different in. The instanceof statement gives the error of "incompatible operand types int and String"
Should I even be using an instanceof statement? Is there a better way to check for this?
This is the whole method:
public static void printMenu() {
Scanner userInput2 = new Scanner(System.in);
String menu = new String(" Please choose from the following menu: \n 1. Rock paper Scissors\n 2. "
+ "Tip Calculator\n 3. "
+ "Number Adding\n 4. Guessing Game\n 5. Random\n 6. Exit");
System.out.println(menu);
int userInt = userInput2.nextInt();
if (userInt == 1) {
System.out.println(" You asked to play Rock Paper Scissors");
System.out.println(" Launching Rock Paper Scissors... \n");
RockPaperScissors gameRun1 = new RockPaperScissors();
gameRun1.main(null);
} else if (userInt == 2) {
System.out.println(" You asked to run the Tip Calculator");
System.out.println(" Launching the Tip Calculator... \n");
TipCalculator gameRun2 = new TipCalculator();
gameRun2.main(null);
} else if (userInt == 3) {
System.out.println(" You asked to run the Number Adding game");
System.out.println(" Launching the Number Adding game... \n");
NumberAddingGame gameRun3 = new NumberAddingGame();
gameRun3.main(null);
} else if (userInt == 4) {
System.out.println(" You asked to play GuessingGame");
System.out.println(" Launching GuessingGame... \n");
GuessingGame gameRun4 = new GuessingGame();
gameRun4.main(null);
} else if (userInt == 5) {
System.out.println(" You asked for a random game");
option5();
} else if (userInt == 6) {
System.out.println( "Thank you for using Conner's Sentinel");
// figure out how to terminate the program from here
} else if (userInt != 1 && userInt != 2 && userInt != 3 && userInt != 4 && userInt != 5 && userInt !=6
|| userInt instanceof String {
System.out.println("Not a valid input, type 1-6");
printMenu();
}
printMenu();
}
There is no way to check if the next input was an int like you are doing (userInput2.nextInt() can only return an int), instead you have to check before you assign the result. Something like,
if (userInput2.hasNextInt()) {
int userInt = userInput2.nextInt();
if (userInt == 1) {
System.out.println(" You asked to play Rock Paper Scissors");
System.out.println(" Launching Rock Paper Scissors... \n");
RockPaperScissors gameRun1 = new RockPaperScissors();
gameRun1.main(null);
} else if (userInt == 2) {
System.out.println(" You asked to run the Tip Calculator");
System.out.println(" Launching the Tip Calculator... \n");
TipCalculator gameRun2 = new TipCalculator();
gameRun2.main(null);
} else if (userInt == 3) {
System.out.println(" You asked to run the Number Adding game");
System.out.println(" Launching the Number Adding game... \n");
NumberAddingGame gameRun3 = new NumberAddingGame();
gameRun3.main(null);
} else if (userInt == 4) {
System.out.println(" You asked to play GuessingGame");
System.out.println(" Launching GuessingGame... \n");
GuessingGame gameRun4 = new GuessingGame();
gameRun4.main(null);
} else if (userInt == 5) {
System.out.println(" You asked for a random game");
option5();
} else if (userInt == 6) {
System.out.println("Thank you for using Conner's Sentinel");
// figure out how to terminate the program from here
} else {
System.out.println("Not a valid input, type 1-6");
printMenu();
}
} else {
userInput2.nextLine(); // <-- consume the non-number
System.out.println("Not a valid number, type 1-6");
printMenu();
}
Instead of "expecting" an int...
int userInt = userInput2.nextInt();
You should "expect" a String...
int actualInput = userInput2.nextLine();
From this you could then use Integer.parseInt(String) in an attempt to parse the String to an int, this will give you your first chance to validate the value.
The problem with this is Integer.parseInt(String) can throw a NumberFormatException, and you really should avoid making logic decisions based on exceptions.
Another approach might be to use a regular expression instead, something like...
if (actualInput.matches("^\\d*")) {
// This is a number, safe to parse to int
} else {
// This is not a number and is not safe to be parsed
}
Once you're satisfied that the actualInput is a number, you could use another Scanner to get the next int...
Scanner safeScanner = new Scanner(actualInput);
int userInt = safeScanner.nextInt();
as an example
userInt instanceof String will always be false, since userInt is an int. If it is an int, you don't need to check for instanceof string.
What you meant is to proof check the string from user input with StringUtils.isNumeric and reduce your other expressions to:
if 1<= userInt && userInt <=6
Should I even be using an instanceof statement? Is there a better way
to check for this?
Even if some other string, non numeric, could be converted to int and result into a value between 1 and 6, this way it would be rejected. Keep the numeric check, yes, just the correct one, StringUtils.isNumeric .
If you opt to have userInt as String, instead, then turn the other expression into if 1<= Integer.parseInt(userInt) && Integer.parseInt(userInt) <=6
First of all, after you write something like this:
int userInt = userInput2.nextInt();
your userInt is declared as an int, and can be nothing but a int. So writing something like this makes no sense:
userInt instanceof String
Because here, you already know that userInt is an int, because you declared it so.
The problem (where the exception, or crash as you called it, occurred) is elsewhere. It will happen at the call to nextInt().
Read the documentation for Scanner.nextInt(), under the exceptions, it states:
Throws:
InputMismatchException - if the next token does not match the Integer regular expression, or is out of range
So that is exactly what happens.
You have several choices, two of which:
catch the exception, and handle it the way you want it to be handled
Use of Scanner.hasNextInt().
I already see a growing number of alternative approaches.
Also most people would translate that chain of if/else if statements into a switch/case/default construct.
Then an other problem in your printMenu() method, it is endlessly recursive. Even though it is just user input, and it might have a limited timespan, with limited user entries before it exits, in theory you could reach a situation where you get a StackOverflowException. This implementation begs to be converted from recursive to iterative to avoid overallocation of objects (memory leak) and having a stack that grows forever.

Loop certain IF statements in java

import java.util.Scanner;
public class main {
public static void main(String[] args) {
int number = 0;
Scanner input = new Scanner(System.in);
System.out.print("Please enter the number of sides");
number = input.nextInt();
if (number == 1) {
System.out.println("Circle");
}
if (number == 3) {
System.out.println("Triangle");
}
if (number == 4) {
System.out.println("quadrilateral");
}
else {
System.out.println("Incorrect Input");
}
}
}
Hello, I am trying to use the if statement. Can anyone advise me how to loop if statements? Because I get this as a result for example:
circle
Incorrect Input.
Also, How could I repeat the scanner so it allowed me to type another input?
Currently, the else clause is only associated to the last if block i.e. if (number == 4) {...} This means if any of the other if blocks are executed, it will still print "Incorrect Input". The solution is to use else if instead of separate if's.
if (number == 1) {
System.out.println("Circle");
}else if (number == 3) {
System.out.println("Triangle");
}else if (number == 4) {
System.out.println("quadrilateral");
}
else {
System.out.println("Incorrect Input");
}
You can use switch case (see : https://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html).
And you can check the type of number or string with instanceof.
For your second part question, I guess you're looking for something like a do....while loop, you can set up some condition like if the input result is not a number, then it will stuck in the loop until the user type in a number then only go in the the if, else-if statement

value is not returning from another class

Hi I'm making a game where the player is met with a robot and the robot asks it to guess a number between 1-10. The player has three tries or they die. I've written all my code and the guessing works fine but whenever the play gets it right he still dies. I added a couple of print statements to see what value my code was returning and it seems to be returning the wrong value. Can someone help me out? Thanks.
Goes from this class
if (choice != -1) {
if (john[choice] != null) {
if (john[choice].compPlayerAttack()) {
System.out.print("IT'S GAME OVER MAN!\n");
System.exit(0);
}
else {
System.out.println("Robot appears. Guess a number between 1-10. Get it right and you can pass, or you die. You have three chances.\"");
int answer = 0;
john[choice].toPass(answer);
if (answer== 1) {
System.out.println(answer);
map[x][y].removeJohnPlayer();
}
else { System.out.println(answer);
System.out.print("IT'S GAME OVER MAN!\n");
System.exit(0);
}
To this class
public int toPass(int right){
int hiddenNum = numram.nextInt(MAX_NUMBER);
Scanner input = new Scanner(System.in);
int numOfGuesses = 0;
int a = right;
do {
System.out.println("Enter a number by guessing: ");
int guessedNum = input.nextInt();
numOfGuesses++;
if (guessedNum == hiddenNum) {
System.out.println("Darn! Your number is matched. You may live.");
System.out.println("You have made " + numOfGuesses + " attempts to find the number!");
a = 1;
break;
} else if (guessedNum < hiddenNum) {
System.out.println("Try a bigger number");
} else if (guessedNum > hiddenNum) {
System.out.println("Try a smaller number");
}
} while (numOfGuesses < 3);
System.out.println(a);
return a;
}
Here
john[choice].toPass(answer);
you are ignoring the value returned by your toPass method.
Change it to:
answer = john[choice].toPass(answer);
BTW, there's no reason to pass an argument to your toPass method, since it makes no use of it, and it can't change it (since Java is a pass by value language). A return value is enough.
i.e. change your method to public int toPass().
Another change you should make is to change the return type to boolean. Returning true or false is more readable than returning 1 or 0.

multiple variable for if else statement

I have written some code to check if the user has entered a number between 1 and 5, and now I would also like my code to allow the user to enter the letters A, S, D or M.
Is there a way to combine the code where I can have it identify whether the user has entered 1-5 or A, S, D, M?
How do I edit the code below so the user can enter either an Integer or a character? Do I have to write a snippet of code underneath the loop for it to identify that a user did not enter 1-5 but did enter A, S, D, or M, as in break out of the loop? Or is it a separate loop all together. I am so confused!
import java.util.InputMismatchException;
import java.util.Scanner;
public class Selection {
Scanner readInput = new Scanner(System.in);
int selectionOne() {
int inputInt;
do { //do loop will continue to run until user enters correct response
System.out.print("Please enter a number between 1 and 5, A for Addition, S for subtraction, M for multiplication, or D for division: ");
try {
inputInt = readInput.nextInt(); //user will enter a response
if (inputInt >= 1 && inputInt <=5) {
System.out.print("Thank you");
break; //user entered a number between 1 and 5
} else {
System.out.println("Sorry, you have not entered the correct number, please try again.");
}
continue;
}
catch (final InputMismatchException e) {
System.out.println("You have entered an invalid choice. Try again.");
readInput.nextLine(); // discard non-int input
continue; // loop will continue until correct answer is found
}
} while (true);
return inputInt;
}
}
I suggest instead of using an int input, just use a String input and convert it to an integer when you need to. You can use Integer.parseInt(String) to convert a String to an int.
So when you check if the input is valid, you need to check if the input is equal to "A", "S", "M" or "D", or any values from 1-5 when it is converted to an int.
So to check if it's one of the characters, you could do this:
if (input.equals("A") || input.equals("S") || input.equals("M") || input.equals("D"))
And then to test if it's an int of value 1 through 5, you could do this:
if (Integer.parseInt(input) >= 1 && Integer.parseInt(input) <= 5)
Just parse the input to an int and then check the range as you already have done.
The return type of this method will be String now, instead of int. If you need it to be an int for whatever reason, you can just parse the value to an int and then return that instead. But I just returned it as a String.
The last thing I changed was the catch block. Now, instead of an InputMismatchException (because they can enter Strings now, I changed it to NumberFormatException, which would happen if a String that could not be converted to an int was attempted to be. For example, Integer.parseInt("hello") will throw a NumberFomatException because "hello" can not be represented as an integer. But, Integer.parseInt("1") would be fine and would return 1.
Note that you should test the String equivalence first so that you don't go into your block before you have a chance to test all conditions you need to.
The method would look like this:
String selectionOne() {
String input;
do { //do loop will continue to run until user enters correct response
System.out.print("Please enter a number between 1 and 5, A for Addition, S for subtraction, M for multiplication, or D for division: ");
try {
input = readInput.nextLine(); //user will enter a response
if (input.equals("A") || input.equals("S") || input.equals("M") || input.equals("D")) {
System.out.println("Thank you");
break; //user entered a character of A, S, M, or D
} else if (Integer.parseInt(input) >= 1 && Integer.parseInt(input) <= 5) {
System.out.println("Thank you");
break; //user entered a number between 1 and 5
} else {
System.out.println("Sorry, you have not entered the correct number, please try again.");
}
continue;
}
catch (final NumberFormatException e) {
System.out.println("You have entered an invalid choice. Try again.");
continue; // loop will continue until correct answer is found
}
} while (true);
return input;
}
As #MarsAtomic mentioned, first thing you should change your input to String instead of an int so you can easily handle both characters and digits.
Change:
int inputInt;
To:
String input;
Then change:
inputInt = readInput.nextInt();
To:
input = readInput.next();
To accommodate reading String instead of int.
Now you reach at 2 main cases (and 2 subcases):
1) input is a single character
a) input is a single digit from 1-5
b) input is a single character from the set ('A', 'S', 'D', 'M')
2) input is an error value
Also, since you are not calling Scanner.nextInt, you don't need to use the try/catch statement and can print your errors in else blocks.
Furthermore, you should have your method return a char or a String instead of an int so you can return both 1-5 or A,S,D,M. I will assume you want to return a char. If you want to return a String instead, you can return input instead of return val in the code bellow.
NOTE: The code bellow can be simplified and shortened, I just added variables and comments in an attempt to make each step clear to what is being read or converted. You can look at #mikeyaworski's answer for a more concise way of doing this.
Here is how your code could look like:
char selectionOne() {
String input;
do {
input = readInput.next();
// check if input is a single character
if(input.length() == 1) {
char val = input.charAt(0);
// check if input is a single digit from 1-5
if(Character.isDigit(val)) {
int digit = Integer.parseInt(input);
if (digit >= 1 && digit <=5) {
System.out.print("Thank you");
return val; // no need to break, can return the correct digit right here
} else {
System.out.println("Sorry, you have not entered the correct number, please try again.");
}
} else {
// check if input is in our valid set of characters
if(val == 'A' || val == 'S' || val == 'M' || val == 'D') {
System.out.print("Thank you");
return val; // return the correct character
} else {
System.out.println("Sorry, you have not entered the correct character, please try again.");
}
}
} else {
System.out.println("Sorry, you have not entered the correct input format, please try again.");
}
} while(true);
}
If your input can be both characters and letters, why not change to looking for a char or String? Then, you can look for "1" or "A" without any trouble.

Java: Loop issues

I'm writing a relatively simple Java program that calculates discounts for shoppers if they have certain vouchers or bonuses. It's working okay, but I have an issue when the program asks the user if they have any vouchers.
If they type "n", they still have to go through the loop as if they responded with "y" once before they can exit. I know it's probably a dumb mistake in there somewhere, but it's been driving me crazy and I'd appreciate a pair of fresh eyes to once it over.
do {
System.out.println("Please enter the total price of the goods");
price = keyboard.nextDouble();
if (price < limits[0] || price > limits[1]) {
System.out.println("Invalid price. Please try again");
validPrice = false;
} else {
validPrice = true;
}
} while (!validPrice);
keyboard.nextLine();
do {
System.out.println("Does the customer have any additional discounts? y/n");
choice = keyboard.nextLine();
if (!choice.matches(inputRegexMatchPattern)) {
System.out.println("Invalid input – please re-enter");
} else if (choice.toLowerCase().charAt(0) == 'y') ;
{
System.out.println(choice);
do {
System.out.println("What type of discount does the customer have? [L]oyalty Card/[D]iscount Voucher");
input = keyboard.nextLine();
if (!input.matches(discountRegexMatchPattern)) {
System.out.println("Invalid input – please re-enter");
}
} while (!input.matches(discountRegexMatchPattern));
if (input.charAt(0) == 'l' || input.charAt(0) == 'L') {
voucherDiscounts += voucherDiscountsArray[0];
System.out.println("Loyalty Card discount accepted");
} else if (input.charAt(0) == 'd' || input.charAt(0) == 'D') {
voucherDiscounts += voucherDiscountsArray[1];
System.out.println("Discount Voucher accepted");
}
}
} while (!(choice.toLowerCase().charAt(0) == 'n'));
You have a semicolon here:
else if (choice.toLowerCase().charAt(0) == 'y') ;
What that means is your loop will continue to execute in spite of the selection you make. Java interprets this if statement as not having any body.
Remove the semicolon and you should be good to go.
The do while construct always performs the content of the loop BEFORE it actually tests the condition.
I guess what you want here is a simple while loop.

Categories