(I have a homework question that I've been stuck on that concerns "do-while loops" in Java. )
It is asking me to have a do-while loop that continues to prompt a user to enter a "number less than 100", up until the entered number is actually less than 100.
(It will run three tests:)
Ex: Test 1:
For the user input 123, 395, 25, the expected output is:
Enter a number (<100):
Enter a number (<100):
Enter a number (<100):
Your number < 100 is: 25
(Here's my code so far:)
public class NumberPrompt {
public static void main (String [] args) {
Scanner scnr = new Scanner(System.in);
int userInput = 0;
do {
System.out.println("Enter a number (<100):" );
System.out.println("Enter a number (<100):" );
System.out.println("Enter a number (<100):" );
userInput = userInput + 25;
} while (userInput > 100);
System.out.print("");
System.out.println("Your number < 100 is: " + userInput);
}
(My Output matches exactly with the Test 1 results above, but I realize I'm not setting up the loop right at all because when it does the second test of "-9", the output exactly the same as my first test:)
Enter a number (<100):
Enter a number (<100):
Enter a number (<100):
Your number < 100 is: 25
(This is my first week being introduced to loops, I searched around for some walk through examples but I haven't found many "Do" while loops that remind me of this one. If anyone has some good tips or guides to point me to I would greatly appreciate it.)
You don't need to write System.out.println("Enter a number (<100):" ); three times. It will be displayed automatically every time when user inputs value less than 100. And you are assigning value to userInput by your own instead of taking input from user. You should write the code given below.
do {
System.out.println("Enter a number (<100):" );
userInput = scnr.nextInt();
} while (userInput > 100);
System.out.println("Your number < 100 is " + userInput);
1.Reading value
As Juan's comment suggested, you are not reading user input value. Basically, this is done with nextInt() method. Morever, int is a primitive type and must be initialised. You choose the value of 0. So why not choosing 101 so that it starts with an incorrect value? Then you are sure that the while loop will be triggered:
public static void main(String... aArgs) {
Scanner sc = new Scanner(System.in);
// initialise at 101 to trigger the while loop
int userInput = 101;
// as we start at 101, it will enter the loop at least once
while (userInput > 100) {
System.out.println("Enter a number (<100):");
userInput = sc.nextInt();
}
System.out.println("Your number < 100 is: " + userInput);
}
2.Never trust the user
2.1 Exception catching
The above code may be sufficient for your assignement. However, for learning sake, I have a fundamental principal: never trust the user!. If the previous example, if an user inputs azerty, then your program will throw you an InputMismatchException. What's that? This error tells you that the scanner expected an int and you fed him with something else: it throws this up.
A simple analogy is: the scanner can only eat apple. You give him a pear: he takes a bit and throws that up: "I can only eat apple". To prevent your scanner from throwing up, you can ask him: "try a bit, and if this is not an apple, let's try something else"
In code, it gives you something like:
public static void main(String... aArgs) {
Scanner sc = new Scanner(System.in);
// initialise at 101 to trigger the while loop
int userInput = 101;
// as we start at 101, it will enter the loop at least once
while (userInput > 100) {
// tell the scanner to try something
try {
System.out.println("Enter a number (<100):");
userInput = sc.nextInt();
}
// if the input is not a number, tell him do this this:
catch (InputMismatchException e) {
System.out.println("This is not a number!");
}
}
System.out.println("Your number < 100 is: " + userInput);
}
If you are not familiar with try/catch clause, you can read this
2.1 Scanner feeding
The above code is not working. How? If you enter something which is not a number, like "aaaa", you will have an infinite of
Enter a number (<100):
This is not a number!
Why? Because the scanner did not throw your input out. Basically, he either should eat the pear (but he will throw up) or throw it to the dust bin but you never told him to throw it to the dust bin! The scanner needs to consume the input before trying the next input.
In a nutshell:
userInput starts at 101 so the while loop is entered
You enter aaaa.
The InputMismatchException is caught. The "This is not a number!" is printed out
userInput value did not change (still at 101), so the loop keeps going
At this stage, the scanner did not consume the previous input so the next input is still aaaa.
Go to 3. and start again
How to fix this? By telling the scanner to consume the input with next():
public static void main(String... aArgs) {
Scanner scnr = new Scanner(System.in);
// initialise at 101 to trigger the while loop
int userInput = 101;
// as we start at 101, it will enter the loop at least once
while (userInput > 100) {
// tell the scanner to try something
try {
System.out.println("Enter a number (<100):");
userInput = scnr.nextInt();
}
// if the input is not a number, tell him do this this:
catch (InputMismatchException e) {
// consume the incorrect input with scnr.next()
// so that user can enter another input
System.out.println(scnr.next() + " is not a number!");
}
}
System.out.println("Your number < 100 is: " + userInput);
}
Related
The questions are in the comments of the code, sorry for that, I thought it's neater, as the flow is important, I guess...
import java.util.Scanner;
public class ReadingUserInput {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Please, enter 10 numbers, for example, from 1 to 100!");
int number = 0;
int total = 0;
int counter = 0;
while (counter < 10) {
System.out.println("Enter number #" + (counter + 1));
boolean hasNextInt = scanner.hasNextInt(); // here we open the prompt for user to enter the value/s*
// internally, we are ready to check if the input is going to be int
// user types the value/s and clicks enter
// let's presume, he/she typed '3'
// internally, user's input is like that (if Windows**) - '3\n'
// because when user presses Enter - \n is added to what he/she typed
if (hasNextInt) { // the app checks, ant it's int, that is, it's OK (true)
number = scanner.nextInt(); //here the application grabs user's input
//but, internally, it grabs only '3', because 'nextInt()' grabs only ints
// and doesn't "care" about the new feed/line - \n - character
// so, '\n' is left in Scanner's buffer!
counter++;
total += number;
} else {
System.out.println("Invalid Input! Try again!");
}
//scanner.nextLine(); // let's presume, this commented line, on the left of this line of comment, is absent in our code
// the flow of our code goes to boolean hasNextInt = scanner.hasNextInt();
// and again internally, we are ready to check if the input is going to be int
// and again the user is prompted (by a blinking cursor) to type his/her input
// and at this moment user types either a numeric again or a non-numeric character (a letter/letters)
// let's presume he/she is typing '4'
// and again, internally, user's input is actually like that (if Windows**) - '4\n'
// but scanner.hasNextInt() says 'OK', for the int is there! and it doesn't care about '\n'
//
// Now, let's presume that user (this time or next time) types 'a'
// Do we actually have 'a\n' ???
// and this time scanner.hasNextInt() says 'Alarm' - 'false'
// thus the input doesn't go to number = scanner.nextInt();
// So, does it mean that 'a\n' (or 'a') remains in Scanner's buffer???
// and it (scanner.hasNextInt()) kicks us to 'else'
// and we have an endless loop:
//Invalid Input! Try again!
//Enter number #...
//Invalid Input! Try again!
//Enter number #...
//Invalid Input! Try again!
//Enter number #...
//Invalid Input! Try again!
//Enter number #...
//Invalid Input! Try again!
//Enter number #...
//Invalid Input! Try again!
//Enter number #...
//Invalid Input! Try again!
//Enter number #...
//Why?
// Is there still 'a' (or 'a\n') and scanner.hasNextInt() throws the flow to 'else' endlessly,
// because "The scanner does not advance past any input"* ???
//
// or: there's only '\n', and again its not int, and we result in endless loop ???
// And finally, is that a different case? https://www.youtube.com/watch?v=_xqzmDyLWvs
// And PS: Is there anything wrong in my description in the comments?
// So what do we 'consume' by scanner.nextLine(); ???
}
scanner.close();
System.out.println("Thank you, your total is " + total);
}
}
// *This is from Oracle :(https://docs.oracle.com/javase/6/docs/api/java/util/Scanner.html#hasNextInt%28%29)
"hasNextInt
public boolean hasNextInt()
Returns true if the next token in this scanner's input can be interpreted as an int value in the default radix using the nextInt() method. The scanner does not advance past any input."
// **https://knowledge.ni.com/KnowledgeArticleDetails?id=kA00Z0000019KZDSA2
Create another scanner object instead and forget about what is left in the internal buffer.
public class ReadingUserInput {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Please, enter 10 numbers, for example, from 1 to 100!");
int number = 0;
int total = 0;
int counter = 0;
while (counter < 10) {
System.out.println("Enter number #" + (counter + 1));
boolean hasNextInt = scanner.hasNextInt();
if (hasNextInt) {
number = scanner.nextInt();
counter++;
total += number;
} else {
System.out.println("Invalid Input! Try again!");
scanner = new Scanner(System.in);
}
}
scanner.close();
System.out.println("Thank you, your total is " + total);
}
}
So I've written a test class to test a program that will allow me to take in number of courses, letter grades, and course credits and then calculate total weighted points, total credits, and GPA within a loop designed for 3 courses max.
However, I need to validate the number of courses and prove that it will run after both an invalid and valid input have been entered.
I've gotten it so that will prompt the user for a valid number of courses after an invalid response, but once the valid response is input the program just stops instead of running like it is supposed to. Can anyone tell me why?
Here's my code:
import java.util.*;
import java.lang.*;
public class ComputeGpa
{
public static void main(String [] args)
{
Gpa grades1 = new Gpa();
Scanner in = new Scanner (System.in);
System.out.println("Enter number of courses: ");
int courses = in.nextInt();
if(courses > 0)
{
int i = 0;
while(i < 3)
{
System.out.println("Please enter a letter grade.");
String letter = in.next();
char result = letter.charAt(0);
System.out.println("How many credits was this class worth?");
int credits = in.nextInt();
grades1.addToTotals(result, credits);
i++;
}
System.out.printf("GPA: %.2f", grades1.calcGpa());
}
else
{
System.out.println("Number of courses must be greater than 0. Please enter a valid number of courses.");
courses = in.nextInt();
}
}
}
The output for that is as follows:
Enter number of courses:
-2
Number of courses must be greater than 0. Please enter a valid number of courses.
3
And then the program stops running. Where Am I going wrong? I thought the in.next() on the letter String would fix this problem but apparently I was wrong. Any ideas?
Your flow is currently if/else.
int foo = ...;
if(foo > 0) {
//your grade stuff
}
else {
//ask for reinput
}
What ends up happening is you catch the problem input once, but never give your flow the opportunity to check it again.
Instead, use a while loop over an if/else layout, to force re-entry until you get the exact information you want, then continue.
System.out.println("Enter number of courses: ");
int courses = in.nextInt();
while(courses < 0) {
System.out.println("Number of courses must be greater than 0. Please enter a valid number of courses.");
courses = in.nextInt();
}
int i = 0;
//...
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'm making a simple program that asks the user to input five numbers between 0-19. I would like to add something (like an if statement) after every number to make sure it's within that range. If not, the program should say "please read instructions again" and will then System.exit(0). This is the piece of the code that is relevant:
System.out.println("Please enter 5 numbers between 0 and 19");
System.out.print("1st Number: ");
userNum1 = scan.nextInt();
System.out.print("2nd Number: ");
userNum2 = scan.nextInt();
System.out.print("3rd Number: ");
userNum3 = scan.nextInt();
System.out.print("4th Number: ");
userNum4 = scan.nextInt();
System.out.print("5th Number: ");
userNum5 = scan.nextInt();
Any help would be greatly appreciated.
You can put this after each of your inputs, but you might want to think about putting this logic into its own method, then you can reuse the code and just call it with something like validateInput(userNum1);.
Replace val with your actual variable names.
if (val < 0 || val > 19) {
System.out.println("please read the instructions again");
System.exit(0);
}
First of all, I would create a for-loop that iterates N times, with N being the number of numbers you want to ask for (in your case, 5). Imagine your example with 50 numbers; it would be very repetitive.
Then, when you get each number with scan.nextInt() within your for-loop, you can validate however you want:
if (userNum < 0 || userNum > 19) {
// print error message, and quit here
}
Also, instead of just exiting when they input a number outside the range, you could have your logic inside a while loop so that it re-prompts them for the numbers. This way the user doesn't have to restart the application. Something like:
boolean runApplication = true;
while(runApplication) {
// do your for-loop with user input scanning
}
Then set the runApplication flag as needed based on whether or not the user put in valid numbers.
This code will do the trick for you, i added some securities :
public static void main(String[] args) {
int count = 1;
Scanner scan = new Scanner(System.in);
List<Integer> myNumbers = new ArrayList<Integer>();
System.out.println("Please enter 5 numbers between 0 and 19");
do {
System.out.println("Enter Number "+count+" ");
if(scan.hasNextInt()){
int input = scan.nextInt();
if(input >= 0 && input <= 19){
myNumbers.add(input);
count++;
}else{
System.out.println("Please read instructions again");
System.exit(0);
}
}else{
scan.nextLine();
System.out.println("Enter a valid Integer value");
}
}while(count < 6);
/* NUMBERS */
System.out.println("\n/** MY NUMBERS **/\n");
for (Integer myNumber : myNumbers) {
System.out.println(myNumber);
}
}
Hope it helps
Since you already know how many numbers you want the user to input, I suggest you use a for loop. It makes your code more elegant and you can add as many more entries as you want by changing the end condition of the loop. The only reason it looks long is because number 1, 2, 3 all end in a different format i.e firST secoND thiRD, but the rest of the numbers all end with TH. This is why I had to implement some if else statements inside the loop.
To explain the code, every time it loops it first tells the user the count of the number he/she is entering. Then numEntry is updated every time the loop loops, therefore you do not need to assign multiple inputs to multiple variables. It is more efficient to update the same variable as you go on. If the input the user inputs is less than 0 OR it is more than 19, the system exits after an error message.
System.out.println("Please enter a number between 0 and 19");
Scanner scan = new Scanner(System.in);
for(int i = 1; i <=5; i++){
if(i == 1)
System.out.println("1st Number");
else if(i == 2)
System.out.println("2nd Number");
else if(i == 3)
System.out.println("3rd Number");
else
System.out.println(i + "th Number");
int numEntry = scan.nextInt();
if(numEntry < 0 || numEntry > 19){
System.out.println("Please read instructions again.");
System.exit(1);
}
I need to ask the user to enter a positive non-zero integer from the console that I will use as a product number in my program.
If I enter any non-integer value, the program correctly enters the while loop.
If I enter a 0 or a negative integer, the program correctly throws the exception (which I catch and handle elsewhere).
When I just press the enter key (or end of line character) it seems that the program just puts the console to another line. I want it to enter the while loop to display the error message. I think the cause is that hasNextInt() will wait until the token is a non end of line character input.
private static void validateProductNumber() throws InvalidProductNumberException {
Scanner keyboard = new Scanner(System.in);
int number;
while(!keyboard.hasNextInt()) {
System.out.println("Number must be an integer. Try again. ");
System.out.println("Enter a new number: ");
keyboard.next();
}
number = keyboard.nextInt();
if (number <= 0)
throw new InvalidProductNumberException();
newNumber = number;
}
Is there another way I can implement my input validation with Scanner class so that it works correctly for all situations?
You can change your loop as follows:
while(true) {
try {
System.out.println("Enter a new number: ");
//read the line and parse it
number = Integer.parseInt(keyboard.nextLine());
break; //break the loop if the input is a valid integer
} catch(Exception ex) {
//print the error message if the input is incorrect
System.out.println("Number must be an integer. Try again. ");
}
}
if (number <= 0)
//...