try/catch infinite loop? [duplicate] - java

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.)

Related

Java - Try/Catch NumberFormatException uses a former value?

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());
}
}

Java Try-catch block, Catch block does not re-prompt the user for a new value [duplicate]

This question already has answers here:
try/catch with InputMismatchException creates infinite loop [duplicate]
(7 answers)
Closed 6 years ago.
I am new to Java and would like to ask you a question.
I have written the below code where "numOfThreads" should be assigned a valid int value by the user through the Console.
However, I would like to achieve a result where if the input is incorrect and we go in the catch block, the user should be re-prompted to enter "numOfThreads" until it is of correct type and range.
For some reason I seem to go into infinite loop. Can you please assist? Thanks :)
import java.util.Scanner;
public class Main {
public static void main(String args[]){
int numOfThreads;
boolean promptUser = true;
Scanner keyboard = new Scanner(System.in);
while (promptUser)
{
try{
numOfThreads = keyboard.nextInt();
promptUser = false;
}
catch(Exception e){
System.out.println("Entry is not correct and the following exception is returned: " + e);
numOfThreads = keyboard.nextInt(); // DOES NOT SEEM TO BE ASKING FOR A NEW INPUT
}
}
}
}
it doesn´t because nextInt tries to consume the last token. When there is an invalid input it can´t consume it. As a result a following nextInt call wont be able to consume it either. write a keyboard.nextLine before numOfThreads = keyboard.nextInt(); and you are fine.
catch(Exception e){
System.out.println("Entry is not correct and the following exception is returned: " + e);
// this consumes the invalid token now
keyboard.nextLine();
numOfThreads = keyboard.nextInt(); // It wasn´t able to get the next input as the previous was still invalid
// I´d still rewrite it a little bit, as this keyboard.nextInt is now vulnerable to throw a direct exception to the main
}

How do I take input along with handling exceptions?

I want to take an integer input from the user. I am using a try-catch exception so that if the input is not an int it asks the user for another input. I have written the following code:
while (flag==true) {
try {
System.out.println("Enter the encryption key!");
k = input.nextInt();
flag = false;
}
catch (InputMismatchException ex) {
System.out.println("Please enter integer value!(");
}
}
But when an exception occurs the loop keeps on printing
"Enter the encryption key!"
"Please enter integer value!"
infinitely because the scanner input does not wait to take another input.
How can I tackle with this problem?
You could try to use
input.nextLine()
because then it waits until you press enter. But then you need to parse it to an int if i remember correctly.
You should call next inside the catch clause, this will solve the problem.
See the docs - Scanner:
When a scanner throws an InputMismatchException, the scanner will not
pass the token that caused the exception, so that it may be retrieved
or skipped via some other method.
Without having next in the catch clause, input.nextInt(); will keep reading the same token, adding next will consume that token.
You should go with suggestion of Maroun Maroun that looks more clean to me.
One other way is to re-initialize the Scanner in loop.
boolean flag = false;
while (!flag) {
try {
input = new Scanner(System.in);//Initialize it here
//....

try-catch statement not returning to try block when catching exception

I have a method that a wrote. This method just scans for a user entered integer input. If the user enters a character value it will throw an input mismatch exception, which is handled in my Try-Catch statement. The problem is that, if the user inputs anything that is not a number, and then an exception is thrown, I need the method to loop back around to ask the user for input again. To my understanding, a Try catch statement automatically loops back to the Try block if an error is caught. Is this not correct? Please advise.
Here is my method (it's pretty simple):
public static int getMask() {
//Prompt user to enter integer mask
Scanner keyboard = new Scanner(System.in);
int output = 0;
try{
System.out.print("Enter the encryption mask: ");
output = keyboard.nextInt();
}
catch(Exception e){
System.out.println("Please enter a number, mask must be numeric");
}
return output;
}//end of getMask method
Here is how the method is implemented into my program:
//get integer mask from user input
int mask = getMask();
System.out.println("TEMP mask Value is: " + mask);
/***********************************/
Here is my updated code. It creates an infinate loop that I can't escape. I don't understand why I am struggling with this so much. Please help.
public static int getMask() {
//Prompt user to enter integer mask
Scanner keyboard = new Scanner(System.in);
int output = 0;
boolean validInput = true;
do{
try {
System.out.print("Enter the encryption mask: ");
output = keyboard.nextInt();
validInput = true;
}
catch(InputMismatchException e){
System.out.println("Please enter a number, mask must be numeric");
validInput = false;
}
}while(!(validInput));
return output;
/********************/FINAL_ANSWER
I was able to get it finally. I think I just need to study boolean logic more. Sometimes it makes my head spin. Implementing the loop with an integer test worked fine. My own user error I suppose. Here is my final code working correctly with better exception handling. Let me know in the comments if you have any criticisms.
//get integer mask from user input
int repeat = 1;
int mask = 0;
do{
try{
mask = getMask();
repeat = 1;
}
catch(InputMismatchException e){
repeat = 0;
}
}while(repeat==0);
To my understanding, a Try catch statement automatically loops back to the Try block if an error is caught. Is this not correct?
No this is not correct, and I'm curious as to how you arrived at that understanding.
You have a few options. For example (this will not work as-is but let's talk about error handling first, then read below):
// Code for illustrative purposes but see comments on nextInt() below; this
// is not a working example as-is.
int output = 0;
while (true) {
try{
System.out.print("Enter the encryption mask: ");
output = keyboard.nextInt();
break;
}
catch(Exception e){
System.out.println("Please enter a number, mask must be numeric");
}
}
Among others; your choice of option usually depends on your preferred tastes (e.g. fge's answer is the same idea but slightly different), but in most cases is a direct reflection of what you are trying to do: "Keep asking until the user enters a valid number."
Note also, like fge mentioned, you should generally catch the tightest exception possible that you are prepared to handle. nextInt() throws a few different exceptions but your interest is specifically in an InputMismatchException. You are not prepared to handle, e.g., an IllegalStateException -- not to mention that it will make debugging/testing difficult if unexpected exceptions are thrown but your program pretends they are simply related to invalid input (and thus never notifies you that a different problem occurred).
Now, that said, Scanner.nextInt() has another issue here, where the token is left on the stream if it cannot be parsed as an integer. This will leave you stuck in a loop if you don't take that token off the stream. To that end you actually want to use either next() or nextLine(), so that the token is always consumed no matter what; then you can parse with Integer.parseInt(), e.g.:
int output = 0;
while (true) {
try{
System.out.print("Enter the encryption mask: ");
String response = keyboard.next(); // or nextLine(), depending on requirements
output = Integer.parseInt(response);
break;
}
catch(NumberFormatException e){ // <- note specific exception type
System.out.println("Please enter a number, mask must be numeric");
}
}
Note that this still directly reflects what you want to do: "Keep asking until the user enters a valid number, but consume the input no matter what they enter."
To my understanding, a Try catch statement automatically loops back to the Try block if an error is caught. Is this not correct?
It is indeed not correct. A try block will be executed only once.
You can use this to "work around" it (although JasonC's answer is more solid -- go with that):
boolean validInput = false;
while (!validInput) {
try {
System.out.print("Enter the encryption mask: ");
output = keyboard.nextInt();
validInput = true;
}
catch(Exception e) {
keyboard.nextLine(); // swallow token!
System.out.println("Please enter a number, mask must be numeric");
}
}
return output;
Further note: you should NOT be catching Exception but a more specific exception class.
As stated in the comments, try-catch -blocks don't loop. Use a for or while if you want looping.

Java: Infinite loop using Scanner in.hasNextInt()

I am using the following code:
while (invalidInput)
{
// ask the user to specify a number to update the times by
System.out.print("Specify an integer between 0 and 5: ");
if (in.hasNextInt())
{
// get the update value
updateValue = in.nextInt();
// check to see if it was within range
if (updateValue >= 0 && updateValue <= 5)
{
invalidInput = false;
}
else
{
System.out.println("You have not entered a number between 0 and 5. Try again.");
}
} else
{
System.out.println("You have entered an invalid input. Try again.");
}
}
However, if I enter a 'w' it will tell me "You have entered invalid input. Try Again." and then it will go into an infinite loop showing the text "Specify an integer between 0 and 5: You have entered an invalid input. Try again."
Why is this happening? Isn't the program supposed to wait for the user to input and press enter each time it reaches the statement:
if (in.hasNextInt())
In your last else block, you need to clear the 'w' or other invalid input from the Scanner. You can do this by calling next() on the Scanner and ignoring its return value to throw away that invalid input, as follows:
else
{
System.out.println("You have entered an invalid input. Try again.");
in.next();
}
The problem was that you did not advance the Scanner past the problematic input. From hasNextInt() documentation:
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.
This is true of all hasNextXXX() methods: they return true or false, without advancing the Scanner.
Here's a snippet to illustrate the problem:
String input = "1 2 3 oops 4 5 6";
Scanner sc = new Scanner(input);
while (sc.hasNext()) {
if (sc.hasNextInt()) {
int num = sc.nextInt();
System.out.println("Got " + num);
} else {
System.out.println("int, please!");
//sc.next(); // uncomment to fix!
}
}
You will find that this program will go into an infinite loop, asking int, please! repeatedly.
If you uncomment the sc.next() statement, then it will make the Scanner go past the token that fails hasNextInt(). The program would then print:
Got 1
Got 2
Got 3
int, please!
Got 4
Got 5
Got 6
The fact that a failed hasNextXXX() check doesn't skip the input is intentional: it allows you to perform additional checks on that token if necessary. Here's an example to illustrate:
String input = " 1 true foo 2 false bar 3 ";
Scanner sc = new Scanner(input);
while (sc.hasNext()) {
if (sc.hasNextInt()) {
System.out.println("(int) " + sc.nextInt());
} else if (sc.hasNextBoolean()) {
System.out.println("(boolean) " + sc.nextBoolean());
} else {
System.out.println(sc.next());
}
}
If you run this program, it will output the following:
(int) 1
(boolean) true
foo
(int) 2
(boolean) false
bar
(int) 3
This statement by Ben S. about the non-blocking call is false:
Also, hasNextInt() does not block. It's the non-blocking check to see if a future next call could get input without blocking.
...although I do recognize that the documentation can easily be misread to give this opinion, and the name itself implies it is to be used for this purpose. The relevant quote, with emphasis added:
The next() and hasNext() methods and their primitive-type companion methods (such as nextInt() and hasNextInt()) first skip any input that matches the delimiter pattern, and then attempt to return the next token. Both hasNext and next methods may block waiting for further input. Whether a hasNext method blocks has no connection to whether or not its associated next method will block.
It is a subtle point, to be sure. Either saying "Both the hasNext and next methods", or "Both hasnext() and next()" would have implied that the companion methods would act differently. But seeing as they conform to the same naming convention (and the documentation, of course), it's reasonable to expect they act the same, and hasNext()
clearly says that it can block.
Meta note: this should probably be a comment to the incorrect post, but it seems that as a new user I can only post this answer (or edit the wiki which seems to be preferred for sytlistic changes, not those of substance).
Flag variables are too error prone to use. Use explicit loop control with comments instead. Also, hasNextInt() does not block. It's the non-blocking check to see if a future next call could get input without blocking. If you want to block, use the nextInt() method.
// Scanner that will read the integer
final Scanner in = new Scanner(System.in);
int inputInt;
do { // Loop until we have correct input
System.out.print("Specify an integer between 0 and 5: ");
try {
inputInt = in.nextInt(); // Blocks for user input
if (inputInt >= 0 && inputInt <= 5) {
break; // Got valid input, stop looping
} else {
System.out.println("You have not entered a number between 0 and 5. Try again.");
continue; // restart loop, wrong number
}
} catch (final InputMismatchException e) {
System.out.println("You have entered an invalid input. Try again.");
in.next(); // discard non-int input
continue; // restart loop, didn't get an integer input
}
} while (true);

Categories

Resources