When I run my code it works fine until it gets to the point where my if statement evaluates the answer string. It will always run the first if statement no matter what I input into the scanner object. And if I take out the scanner.nextLine(); then it will not let me enter any input for the answer object.
public class ExceptionTest {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
boolean statement = true;
int total;
String answer = null;
do{
try{
System.out.println("Please enter the amount of Trees:");
int trees = scanner.nextInt();
if(trees < 0){
throw new InvalidNumberException();
}
System.out.printf("Amount of fruit produced is: %d%n", trees * 10);
System.out.println("Please enter the amount of people to feed: ");
int people = scanner.nextInt();
scanner.nextLine();
total = trees * 10 - people * 2;
System.out.printf("The amount of fruit left over is: %d%n", total);
statement = false;
}
catch(InvalidNumberException e){
System.out.println(e.getMessage());
scanner.nextLine();}
}
while(statement);
System.out.println("Would you like to donate the rest of the fruit? Y or N:");
try{
answer = scanner.nextLine();
if(answer == "Y"){
System.out.println("Your a good person.");
}else if(answer == "N"){
System.out.println("Have a nice day.");
}else {
throw new NumberFormatException();
}
}
catch(NumberFormatException e){
System.out.println(e.getMessage());
scanner.nextLine();
}
}
}
There are three things here:
The first call to scanner.nextLine() gets the user input, but isn't stored in a variable. The answer variable is storing a second, unnecessary, call to scanner.nextLine(). EDIT The reason why scanner.nextLine() is needed is the previous scanner call is to scanner.nextInt(). nextInt() doesn't move the cursor to the next line. See: Scanner is skipping nextLine() after using next() or nextFoo()?.
You can't compare Objects using == and !=. Java's comparison operators test for strict object equality. You don't mean to check for whether they are the same String instance, you mean to check if the two instances store the same text. The correct comparison is !answer.equals("Y").
Think about the logic of the if statement. Think about what the || operator means.
I have seen that you edited your answer which was good because the logic was wrong in there. You should check first if the input was Y or N before verifying it is not in the two. Your problem is pretty simple, it is a common problem regarding the scanner class. Just add String trash = scanner.nextLine(); and remove many unnecessary scanner.nextLine();
String trash = scanner.nextLine();
System.out.println("Would you like to donate the rest of the fruit? Y or N:");
try {
answer = scanner.nextLine();
if (answer.equals("Y")) {
System.out.println("Your a good person.");
} else if (answer.equals("N")) {
System.out.println("Have a nice day.");
} else {
throw new NumberFormatException();
}
} catch (NumberFormatException e) {
System.out.println(e.getMessage());
}
Add String trash whenever the Scanner messes up in your case it was near the answer=scanner.nextLine(); If there are still errors just comment. I am happy to help
Related
In Java, I have two while loops to validate user input and continuously prompt the user if they input the wrong data type. In this program, I only have 2 questions, but I can imagine a scenario where I have more than 10, at which point 10 while loops would be cumbersome code to read and maintain. Is there a more efficient way to check for errors while continuing to prompt the user? My initial thought is to package the while loop and error checks into a separate class function and call it when input is requested.
import java.util.*;
public class IncreaseAge {
public static void main(String args[]){
Scanner userInput = new Scanner(System.in);
boolean validInput = true;
String coolName = "Adam";
int coolAge = 0;
while(validInput){
try{
System.out.print("Hello, what is your first name? ");
coolName = userInput.nextLine();
validInput = false;
}
catch(Exception error){
System.out.println("Invalid input, try again!");
userInput.next();
}
}
validInput = true;
while(validInput){
try{
System.out.print("Hi "+ coolName + "! How old are you?");
coolAge = userInput.nextInt();
validInput = false;
}
catch(Exception error){
System.out.println("Invalid input, try again!");
userInput.next();
}
}
System.out.println("Hello "+ coolName + ", in ten years you will be " + (coolAge+10));
userInput.close();
}
}
Just implement private int getIntegerInput(String prompt) and private String getStringInput(String prompt), each of which will more or less be the same as the two loops you've already coded.
This is a common and frequent way to avoid code repetition - implement "helper" routines to be used in writing your intended functionality.
Even if you don't have repetition to worry about, it's a useful partitioning of code, making it easier to understand - for example, the "get an input" code is clearly distinct from the "process the input" code.
Example:
private String getStringInput(Scanner scanner, String prompt) {
String input = null;
boolean validInput = false;
while (!validInput) {
try {
System.out.print(prompt);
input = scanner.nextLine();
validInput = !input.isEmpty();
}
catch (Exception error) {
System.out.println("Invalid input, try again!");
}
}
return input;
}
Note that I fixed the use of 'validInput' to make sense, and I assume you want to reprompt on an empty input line.
Usage is then like
String coolName = getStringInput(userInput, "What is your first name? ");
I am trying to validate the input that decides whether or not the program does everything again or terminates. While it works enough that Y and N are the only accepted answers, it never does actually hit the catch statement - it only loops until Y or N are entered because of the while loop. I need to fix this so that the exception gets thrown for any other input, but I don't understand what I've done wrong.
public static String validateChoice(Scanner sc, String choice) {
choice = "";
while (!choice.equalsIgnoreCase("Y") && !choice.equalsIgnoreCase("N")) {
try {
System.out.print("Continue? Y/N: ");
choice = sc.nextLine();
} catch (InputMismatchException e) {
System.out.println("Invalid answer. Please answer only Y or N. Lowercase is accepted.");
sc.nextLine();
continue;
}
}
return choice;
}
Because there is no error here, catch statement cannot be reached. InputMismatchException is thrown only when the input type is incorrect. For example, you ask for nextInt() but the input is double. You are using nextLine(), so all input is accepted.
The problem is you are catching InputMismatchException which is never thrown by the code in try.
System.out.print("Continue? Y/N: ");
choice = sc.nextLine();
See this: https://docs.oracle.com/javase/10/docs/api/java/util/Scanner.html#nextLine()
So, to solve your problem, continue if user enters Y otherwise stop looping. It makes more sense to rely on a value to continue and consider everything else as NO.
if(Y){
continue;
} else { //any other value
break;
}
Full code:
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
do {
System.out.println("Do some stuff");
} while (continueCheck(sc));
System.out.println("Completed");
}
public static boolean continueCheck(Scanner sc) {
System.out.print("Continue? Y/N: ");
String choice = sc.nextLine();
return "Y".equalsIgnoreCase(choice.trim());//true only if Y or y is entered
}
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.
boolean loop = false;
double numberOfStudents;
System.out.print("Enter a number: ");
if ((scnr.nextLine().trim().isEmpty()) ) {
loop = true;
}
while (loop) {
System.out.println("Enter a number");
if (scnr.hasNextDouble() ){
System.out.println("Loop has stopped");
numberOfStudents = scnr.nextDouble();
loop = false;
}
}
System.out.println("You're outside the loop!");
I'm trying to get the program to say "Enter a number" until the user has entered an actual number (no white spaces or letters or signs). When the user has entered a number, it sets numberOfStudents equal to that number and breaks out of the loop.
But if you hit enter twice, it doesn't iterate. It only displays "Enter a number" once.
What is wrong with the loop logic? Why isn't it looping until valid input is taken?
For the actual answer to your question of "Why doesn't 'Enter a number' display more than once?" see Tom's comment (update: Tom's answer).
I've rewritten your loop in a way which preserves your code, but also makes it a little easier to handle format exceptions (though at the risk of silently swallowing an exception -- should be acceptable for this use case).
Can be up to you to use this design, here is an SO post on why empty catch blocks can be a bad practice.
public static void main(String args[])
{
boolean loop = true;
double numberOfStudents;
Scanner scnr = new Scanner(System.in);
while(loop){
System.out.print("Enter a number: ");
String input = scnr.nextLine();
try{
numberOfStudents = Double.parseDouble(input);
loop = false;
}catch(NumberFormatException e){
}
}
System.out.println("You're outside the loop!");
}
Output:
Enter a number:
Enter a number:
Enter a number:
Enter a number: 50
You're outside the loop!
First of all: Since you're reading from System.in a call to the input stream will block until the user entered a valid token.
So let's check first scan using your scnr variable:
scnr.nextLine()
nextLine() reads everything til the next line delimiter. So if you just press return, then it will successfully read it and will perform the next stuff.
The next call is:
scnr.hasNextDouble()
This call expects a "real" token and ignores white spaces, except as a delimiter between tokens. So if you just press return again it doesn't actually read that input. So it still waits for more (for the first token). That is why it stucks in your loop and you won't get another "Enter a number" output.
You can fix that by either enter a real token, like a number, or by changing the loop like trobbins said.
I hope you now understand your program flow a bit more :).
While trobbins code basically solves your problem, it's bad practice to use exceptions for flow control.
I used a small regexp to check if the value is a number. But this example is not complete, it will still crash it the user enters for example two decimal points. So you would need to create a proper number check or just use integers where the check is much easier.
Someone in the comments pointed out that people may want to enter scientific notation like 5e10, so this would also be another case to check for. If this is just some code you need as a proof of concept or something quick and dirty, you can go with the exception handling method but in production code you should avoid using exceptions this way.
double numberOfStudents;
Scanner scnr = new Scanner(System.in);
while(true) {
System.out.print("Enter a number: ");
String input = scnr.nextLine().trim();
if(input.matches("^[0-9\\.]{1,}$")) {
System.out.println("Loop has stopped");
numberOfStudents = Double.parseDouble(input);
break;
}
}
System.out.println("You're outside the loop!");
The following code should help you:
double numberOfStudents = 0;
Scanner scnr = new Scanner(System.in);
boolean readValue = false; //Check if the valid input is received
boolean shouldAskForNumber = true; //Need to ask for number again? Case for Enter
do {
if (shouldAskForNumber) {
System.out.print("Enter a number:");
shouldAskForNumber = false;
}
if (scnr.hasNextDouble()) {
numberOfStudents = scnr.nextDouble();
readValue = true;
} else {
String token = scnr.next();
if (!"".equals(token.trim())) { //Check for Enter or space
shouldAskForNumber = true;
}
}
} while (!readValue);
System.out.printf("Value read is %.0f\n", numberOfStudents);
System.out.println("You're outside the loop!");
Update
Understood the following statement in question different way:
But if you hit enter twice, it doesn't loop back. It only displays
"Enter a number" once.
The code is set to print "Enter a number" only once if the user hits RETURN/ENTER or enters space character. You may remove the special check and use the code if needed.
import java.util.Scanner;
public class Testing {
public static boolean checkInt(String s)
{
try
{
Integer.parseInt(s);
return true;
} catch (NumberFormatException ex)
{
return false;
}
}
public static void main(String[] args) {
boolean loop = false;
double numberOfStudents;
Scanner scnr = new Scanner(System.in);
String input = "";
while (!(checkInt(input))) {
System.out.println("Enter a number");
input = scnr.nextLine();
}
numberOfStudents = Integer.parseInt(input);
System.out.println("Number of students: " + numberOfStudents );
}
}
//this code is working fine, if you want you check it out.
//In your code your taking another input if the first is an int/double; if the first input is not a number then you have mentioned to take input again..
Use a debugger to see what the code is actually doing. Here's a guide on debugging in Eclipse. After you have finished debugging your code, you will probably know what the problem is.
Below code will help you
boolean loop = true;
double numberOfStudents;
Scanner scnr = new Scanner(System.in);
System.out.print("Enter a number: ");
String input = scnr.nextLine();
while(!scnr.hasNextDouble()){
System.out.print("Enter a number: ");
try{
numberOfStudents = Double.parseDouble(input);
break;
}catch(NumberFormatException e){
}
input = scnr.nextLine();
}
System.out.println("You're outside the loop!");
The following code is working,
boolean loop = true;
double numberOfStudents;
Scanner scnr=new Scanner(System.in);
while(loop) {
System.out.println("Enter a number");
if ((scnr.nextLine().trim().isEmpty()) ) {
loop = true;
}
if (scnr.hasNextDouble() ){
System.out.println("Loop has stopped");
numberOfStudents = scnr.nextDouble();
loop = false;
}
}
System.out.println("You're outside the loop!");
The output is,
run:
Enter a number
hj
po
Enter a number
lhf
Enter a number
o
Enter a number
p
Enter a number
a
Enter a number
34
Loop has stopped
You're outside the loop!
You have to scan the next line if you want to get more values form the scanner again. The code should be like:
while (loop) {
System.out.println("Enter a number");
if(!(scnr.nextLine().trim().isEmpty())){
if (scnr.hasNextDouble() ){
System.out.println("Loop has stopped");
numberOfStudents = scnr.nextDouble();
loop = false;
}
}
}
I'd like to ask how do i exactly condition what my program does if my user types in a character or a string if i want him to type an integer instead? I tried to do it how i showed here in quotes and also tried with "equals". The second method didn't work the first seems to be behaving strangely the IF part works but ELSE is completely ignored.
public static void main(String[] args){
Scanner input=new Scanner(System.in);
System.out.print("Enter first integer: ");
int number1 = input.nextInt();// prompt
if (number1 == (char)number1){
System.out.println("Ok.");
}
else{
System.out.println("You were supposed to type in an int..");
System.exit(1);
}
System.out.print("Enter second integer: ");
int number2 = input.nextInt();// prompt
int sum =(number1 + number2);
System.out.printf("Your sum is: %d%n", sum);
}
I suggest you to use the regular expression in the hasNext() function as follows to have a finer control, for example use the following pattern if you look for the numbers,
sc.hasNext("[0-9]+")
Here is the documentation for the hasNext(String pattern) function,
public boolean hasNext(Pattern pattern)
Returns true if the next complete token matches the specified pattern. A complete token is prefixed and postfixed by input that matches the delimiter pattern. This method may block while waiting for input. The scanner does not advance past any input.
Here is the simple code to perform the check,
Scanner sc=new Scanner(System.in);
int input = 0;
while(true) {
System.out.println("enter a number");
if(sc.hasNext("[0-9]+")) {
input = sc.nextInt();
break;
} else {
System.out.println("not a number, try again");
sc.next(); // just consume, but ignore as its not a number
}
}
System.out.println("Entered number is : "+input);
You can use a user defined function as shown below and call it
public static boolean isNum(String input)
{
try
{
int d = Integer.parseInt(input);
}
catch(NumberFormatException e)
{
return false;
}
return true;
}
Then you can call this method from your main function.
if(isNum(number1))
I am not sure if I understand your question, but I see this as follows:
Users will always type a sequence of characters from the input, then your program has to check if that String can be converted to Int, if it can not be converted it should prompt back to the user telling the typed data is not an int. In that case your nextInt will throw an InputMismatchException.
Probably a much more elegant solution is to use hasNextInt(10):
public static void main(String[] args){
Scanner input=new Scanner(System.in);
System.out.print("Enter first integer: ");
if (input.hasNextInt(10)){
System.out.println("Ok. Typed number: " + input.nextInt());
}else{
System.out.println("You were supposed to type in an int..");
System.exit(1);
}
[...]
}
Try this,
try {
int number1 = sc.nextInt();// prompt
System.out.println("Ok.");
} catch (InputMismatchException ex) {
System.out.println("You were supposed to type in an int..");
System.exit(1);
}
Scanner.nextInt(); Scans the next token of the input as an int.
Program won't execute beyond this line if input is not int.
So it will never enter else part. Don't do any int validation.
I would suggest always use try/catch block to handle incorrect input and show useful message. Also don't forget to close Scanner object.