This question already has an answer here:
How to use java.util.Scanner to correctly read user input from System.in and act on it?
(1 answer)
Closed 4 years ago.
I have researched while(true) loops for past hour but I was unable to find my answers about this loop.
public class Test {
static Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("Enter Integer: ");
int i = GetAnInteger();
System.out.println("You entered: " + i);
}
public static int GetAnInteger() {
while (true) {
try {
return sc.nextInt();
}
catch (InputMismatchException e) {
sc.next();
System.out.println("That's not an Integer, try again: ");
}
}
}
}
Question 1: We know all the statements in the code will run by the compiler. The purpose of 'while(true)' is to make sure the code runs and it runs indefinitely, the code in the method WILL be executed so why do we need a while(true) loop in the first place?
Question 2: If I remove the 'while(true)' statement, the IDE asks me to create a return statement or make the method as void, why? How does 'while(true)' work in this scenario?
Other posts on Stack Overflow were mostly debating why 'while(true)' is bad or good, I am not interested in this. I am interested in why this code breaks down without 'while(true)' and how do I know when to use 'while(true)' in my other codes?
I searched youtube, java complete reference and stack overflow for past half an hour but couldnt find any answers. This code was taken from "Java for dummies" book and it runs away from explaining the purpose of this while(true) statement.
The purpose of the while(true) is so that it will run until the input is valid and it reaches the return statement. When it reaches the return statement then it will exit the method/loop
This is because there is no guarantee that the try section will be executed. If it isn't then the method needs something to return. You must include a return statement for every possible branch of your method.
Consider the following:
try {
//Oh no! InputMismatchException!!
return sc.nextInt();
//Goes to catch block
} catch (InputMismatchException e) {
sc.next();
System.out.println("That's not an Integer, try again: ");
//executes catch block
}
//Uh oh. Now what? What gets returned?
so why do we need a while(true) loop in the first place?
The while loop allows the user to "try again" if they enter something that isn't an integer. When I run your program, I can do this:
Enter Integer:
this
That's not an Integer, try again:
is
That's not an Integer, try again:
not
That's not an Integer, try again:
an
That's not an Integer, try again:
integer
That's not an Integer, try again:
1
You entered: 1
If I remove the 'while(true)' statement, the IDE asks me to create a return statement or make the method as void, why? How does while(true) work in this scenario?
With the while loop in place, you're guaranteed to eventually return something. Without the while loop, you don't have anything to return if the user doesn't enter an integer. So you have to add something at the end of the method (a default return value, which breaks the intent of the program), or you have to make the method not have a return value at all.
Let's imagine that we delete the while loop, and we add return 0 at the end of the method to make the compiler happy. Now let's try the above scenario again:
Enter Integer:
this
That's not an Integer, try again:
You entered: 0
Obviously this is not what we want!
Related
First post so my apologies if this was done incorrectly (and am also relatively new to programming, so any extraneous tips are also appreciated).
So I have written up a basic calculator program in Java. It works well currently, but I am having a particular issue with NumberFormatException. Here's the code:
private static double spaceTestAndConvert(String numInput){
Scanner input= new Scanner(System.in);
if (numInput.equalsIgnoreCase("quit")){
System.exit(1);
}
else if(numInput.equalsIgnoreCase("C/E")){
Restart();
}
try{
return Double.parseDouble(numInput.trim());
}
catch(NumberFormatException nfe){
numInput = "";
System.out.println("Please enter only one number without any spaces or letters: ");
numInput = input.nextLine();
spaceTestAndConvert(numInput.trim());
return Double.parseDouble(numInput.trim());
}
}
The issue is that after trying to force an error by entering in several inputs which would cause NumberFormatException and then entering in a valid input, the program will crash from a NumberFormatException citing the previous invalid input.
I.E. -
"1 2 3"
loops back
"1 2 q 3"
loops back
"12q3 3 sqw 1"
loops back
"12"
crash - Exception in thread "main" java.lang.NumberFormatException: For input string: "12q3 3 sqw 1"
It only occurs after several occurrences of the exception. I'm curious why it is doing this. Any advice on how to fix this or explanation of what is happening? If you need any other part of the code, please let me know! Thanks!
I don't follow everything that you're saying, but these 2 lines (from within your catch block) look problematic...
spaceTestAndConvert(numInput.trim());
return Double.parseDouble(numInput.trim());
You are calling the spaceTestAndConvert function recursively, but throwing away the value. I don't understand why you would call it and not be interested in the value.
The second line is also a mess. You so carefully surround the first call to Double.parseDouble() with try/catch, but then you call it again within your catch block. If the second Double.parseDouble() generates a NumberFormatException, it will not be caught.
removing the return in catch will solve your problem. because if you have return on it, you are going to return an invalid Number format since you are in a catch. What you want to do is to return a value when it is now valid, you are now actually doing it inside the try. Don't force your program to return the value with error (since it is in a catch) because it will really give you an error.
returning to previous method after you had the right value (because of recursion) will still have the stack of error value aside from success value you gained from the end part because they are different variables.
private static double spaceTestAndConvert(String numInput){
Scanner input= new Scanner(System.in);
if (numInput.equalsIgnoreCase("quit")){
System.exit(1);
}
else if(numInput.equalsIgnoreCase("C/E")){
Restart();
}
try{
return Double.parseDouble(numInput.trim());
}
catch(NumberFormatException nfe){
numInput = "";
System.out.println("Please enter only one number without any spaces or letters: ");
numInput = input.nextLine();
spaceTestAndConvert(numInput.trim());
}
}
So the following code is like a simple game,where the objective to to guess the correct numbers(which are 1 to 5).Anything else is incorrect and the user is given a warning message if they enter similar numbers.The comments would explain the loops and variables declared.
The only problem I have with this code is that I inserted a try catch to take care of strings and that doesn't seem to work.If a string is entered,the while loop continues infinitely.
Also,I realize there are a loop pf looping and conditional statements present in my code,but I couldn't think of anything else.If you have any recommendations to reduce the number of loops and if statements,your help would be greatly appreciated.
public class Tries {
public static void main(String[]args)
{
boolean dataType=false;
int Inp;
Scanner a=new Scanner(System.in);
//The arraylist,List, contains the input that the user enters.Only correct input is entered(1 to 5).
ArrayList<Integer> List=new ArrayList<Integer>();
//This determines how many times the for loop is going to execute.Say the user enters 4,and enters 4 correct inputs,the program will exit.The variable num basically determines what the size of the arraylist List is going to be.
System.out.println("How many tries?");
int num=a.nextInt();
boolean datatype=false;
for(int j=0;j<num;j++)
{
//This while loop is for the try catch.
while(!datatype)
{
Scanner sc=new Scanner(System.in);
//This while loop ensures that the user re enters input when anything other than the correct numbers are entered.
while(List.size()!=num)
{
try
{
System.out.println("\nPick a number: ");
Inp=sc.nextInt();
if(Inp==1 || Inp==2 || Inp==3 || Inp==4 || Inp==5)
{
datatype=true;
System.out.println(j);
if(List.size()==0)
{
List.add(Inp);
}
else if(List.size()>0)
{
if(List.contains(Inp))
{
System.out.println("Already entered.Try again.");
}
else if(!List.contains(Inp))
{
List.add(Inp);
System.out.println("Added");
dataType=true;
System.out.println(List);
}
}
}
else
{
System.out.println("Option not available.");
datatype=false;
}
}
catch(Exception JavaInputMismatch)
{
System.out.println("Option not available.Try again.");
datatype=false;
}
}
}
}
}
}
So, when Inp=sc.nextInt(); fails because the user enters an invalid number, then an InputMismatchException gets thrown. Then you loop again, and eventually attempt to run Inp=sc.nextInt(); again.
The problem though is that the invalid number that was entered is still in the input stream waiting to be read. So in the next loop, when Inp=sc.nextInt(); is attempted again, it doesn't try to read in a new value, it just reads the previous invalid value without allowing you to type anything new. And this keeps happening over and over indefinitely.
The quick fix? You need to clear out the input stream to get rid of the invalid number before attempting to read a new one.
The simplest way to plug that fix in your program is by adding an sc.next(); call in your catch block like this:
catch(Exception JavaInputMismatch)
{
sc.next(); // clear the bad token. Without this, it loops infinitely.
System.out.println("Option not available.Try again.");
datatype=false;
}
There are certainly quite a few other changes/improvements I would make to the program, but I'll admit that I lack the motivation at the moment to address those. Hopefully this will at least unblock you.
EDIT:
I guess I can add a few high level suggestions that can help you:
As was already commented, you shouldn't have 2 Scanner instances reading from System.in.
I would recommend dropping the whole try-catch to detect an invalid number, and instead use sc.hasNextInt() to check before reading the number with sc.nextInt(). Even if you did keep the catch block, I would recommend you make the exception type as specific as possible (e.g. catch(InputMismatchException e)) instead of the catch-all Exception. Otherwise, you risk catching irrelevant exceptions and handling them the wrong way.
You should be able to drop the datatype boolean variable and its associated loop. It's enough that you are looping as long as your list is not full.
In fact, if I'm understanding this correctly, you can probably simplify your loops by only keeping the one that does while(List.size()!=num). I think you can safely get rid of the loop that does for(int j=0;j<num;j++).
Minor detail, but you can express if(Inp==1 || Inp==2 || Inp==3 || Inp==4 || Inp==5) more succinctly like this instead: if(Inp >= 1 && Inp <= 5).
And finally, the logic that determines whether to add the number to the list or not doesn't need to do a bunch of conditions based on the size of the list.
Something like this is sufficient:
if (List.contains(Inp)) {
System.out.println("Already entered.Try again.");
} else {
List.add(Inp);
System.out.println("Added");
System.out.println(List);
}
I hope this helps.
This question already has an answer here:
How to use java.util.Scanner to correctly read user input from System.in and act on it?
(1 answer)
Closed 8 years ago.
I'm attempting to make a java function that returns an int inputted by the user, but won't return until the user inputs a valid number. Here's my initial model of the function:
public int getChoice(){
try{
return scan.nextInt();
}catch(Exception e){
return getChoice();
}
}
scan is declared by Scanner scan = new Scanner(System.in);
This function resulted in a Java.lang.stackOverflowError(hmm... this seems an appropriate website for that...). I figure this is because the function is being constantly called.
I've considered somehow using Integer.valueOf(scan.nextLine())', but the reason I haven't really done anything with it is because at some points, and I can't figure out what determines whether this happens or not, but pressing 'Enter' when the program is calling nextLine() will skip the next nextLine(). I can't really figure out a way around that.
So if anyone could possibly provide me with a Java function that will loop until the user inputs a valid integer, then return that integer, please do so, thank you.
You are getting a bad recursion because the getChoice call inside catch block. To repeat the code indefinitely until the user gives you a valid number use while(true) infinite loop. The code you have to read the line and convert it to Integer it is just fine.
public int getChoice() {
while (true) {
try {
return Integer.valueOf(scan.nextLine());
} catch (Exception e) {
System.out.println("Enter a valid number");
}
}
}
This question already has answers here:
How do I exit a while loop in Java?
(10 answers)
Closed 5 years ago.
I am new to Java and programming in general. I've encountered not exactly a problem, but more like a wall of my ignorance. On my QA Automation courses I was asked to write a simple calculator program in Java, I kept it very basic - you needed to launch the program over again every time you preformed a calculation. I learned about while loops and it seemed the while loop was a good solution to keep the program running. But now I am at another extreme - the loop is infinite. My question is: is there any simple way to exit the program without re-writing the code and the way I've structured my calculator? I don't know how to do it but it would be nice if program would end when user presses [Esc] or prints "Exit". Is there a simple way that I (beginner) would understand and could implement?
import java.io.IOException;
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
int first, second, answer;
String operator;
Scanner s = new Scanner(System.in);
try {
while (true) {
log("Please enter a math equation using +, -, * or /");
first = s.nextInt(); //User enters first number
operator = s.next(); //User enters operator
second = s.nextInt(); //User enters second number
if (operator.contains("+")) {
answer = first + second;
log("" + answer);
}
if (operator.contains("-")) {
answer = first - second;
log("" + answer);
}
if (operator.contains("*")) {
answer = first * second;
log("" + answer);
}
if (operator.contains("/")) {
if (second == 0) {
log("You can't divide by 0");
} else {
answer = first / second;
log("" + answer);
}
}
}
} catch (java.util.InputMismatchException error) {
log("Incorrect input");
}
}
public static void log(String s) {
System.out.println(s);
}
}
Thank you, if you can help me!
P.S. I don't know if it is a correct way to handle exceptions or a very ugly one. I'd appreciate if you could comment on that too.
Yes, use break:
if(endingCondition)
break;
This will break out of the innermost loop.
In order to follow your example and not deviate from it focusing on other code improvements, you should have to change the way you read the parameters, because the way you do it now, you could never read the exit word to get out. In order to do this you can use the following approach:
This will add a new string parameter to read the exit or the first operand (in string format). Then, it will transform it into an int:
int first, second, answer = 0;
String operator, firstParam = "";
Scanner s = new Scanner(System.in);
try {
while (true) {
System.out.println("Please enter a math equation using +, -, * or /, or exit if you want to stop the program");
firstParam = s.next(); //User enters first number or exit
// This first param is read as a String so that we are able to read the word exit
if(firstParam.equals("exit"))
break;
first = Integer.valueOf(firstParam); // This will transform the first parameter to integer, because if it reaches this point, firstParam won't be "exit"
//[... Rest of your program...]
}
} catch (java.util.InputMismatchException error) { ... }
TIPS FOR ERROR HANDLING
1: You don't have to specify the complete reference of the InputMismatchException while in catch block because you have already imported the java.util package
catch (InputMismatchException e)
{
//handle exception here
}
2: In case you are unsure about the type of Exception that can thrown, just catch the object of class Exception. Since Exception is the super class for all the Exceptions, it can handle all exceptions.. This would work perfectly for beginners.
catch (Exception e)
{
//handle exception
}
3: You can handle multiple exceptions for the same try block, each catch handling a particular type of exception. Give it a try.
FOR EXITING THE LOOP
if (s1.contains("EXIT"))
break;
Here s1 is the string, and if the string contains the word EXIT (ALL CAPS ONLY), the loop will terminate.
This question already has answers here:
How to handle infinite loop caused by invalid input (InputMismatchException) using Scanner
(5 answers)
Closed 5 years ago.
Help, I am completely new to java and I am trying to create a loop that will ask for an input from the user which is to be a number. If the user enters anything other than a number I want to catch the exception and try again to get the correct input. I did this with a while loop however it does not give the opportunity after the error for the user to type in anything it loops everything else but that. Please help me to see understand what is wrong and the correct way to do this... Thank you. This is what I have:
import java.util.Scanner;
import java.util.InputMismatchException;
public class simpleExpressions {
public static void main (String[] args) {
Scanner keyboard = new Scanner(System.in);
while ( true ) {
double numOne;
System.out.println("Enter an Expression ");
try {
numOne = keyboard.nextInt();
break;
} catch (Exception E) {
System.out.println("Please input a number only!");
} //end catch
} //end while
} //end main
while ( true )
{
double numOne;
System.out.println("Enter an Expression ");
try {
numOne = keyboard.nextInt();
break;
}
catch (Exception E) {
System.out.println("Please input a number only!");
}
This suffers from several problems:
numOne hasn't been initialized in advance, so it will not be definitely assigned after the try-catch, so you won't be able to refer to it;
if you plan to use numOne after the loop, then you must declare it outside the loop's scope;
(your immediate problem) after an exception you don't call scanner.next() therefore you never consume the invalid token which didn't parse into an int. This makes your code enter an infinite loop upon first encountering invalid input.
Use keyboard.next(); or keyboard.nextLine() in the catch clause to consume invalid token that was left from nextInt.
When InputMismatchException is thrown Scanner is not moving to next token. Instead it gives us opportunity to handle that token using different, more appropriate method like: nextLong(), nextDouble(), nextBoolean().
But if you want to move to other token you need to let scanner read it without problems. To do so use method which can accept any data, like next() or nextLine(). Without it invalid token will not be consumed and in another iteration nextInt() will again try to handle same data throwing again InputMismatchException, causing the infinite loop.
See #MarkoTopolnik answer for details about other problems in your code.
You probably want to use a do...while loop in this case, because you always want to execute the code in the loop at least once.
int numOne;
boolean inputInvalid = true;
do {
System.out.println("Enter an expression.");
try {
numOne = keyboard.nextInt();
inputInvalid = false;
} catch (InputMismatchException ime) {
System.out.println("Please input a number only!");
keyboard.next(); // consume invalid token
}
} while(inputInvalid);
System.out.println("Number entered is " + numOne);
If an exception is thrown then the value of inputInvalid remains true and the loop keeps going around. If an exception is not thrown then inputInvalid becomes false and execution is allowed to leave the loop.
(Added a call to the Scanner next() method to consume the invalid token, based on the advice provided by other answers here.)