Error handling reading ints from Scanner in while loop - java

I am try to catch an exception and get it to repeat, but it just creates an endless loop and then crashes the program... why is it doing this? Is it something wrong with my catch?
I have looked around the web and stackoverflow and can only find answers that don't related to what I am trying to achieve.
boolean bError = true;
System.out.println("How many players");
do
{
try
{
PLAYERS = input.nextInt();
if(PLAYERS > 5)
{
System.out.println("maximum of 5");
}//if
else
{
bError = false;
}
}
catch(InputMismatchException e)
{
System.out.println(e);
bError = true;
}
}while(bError && PLAYERS > 5);

It goes into an endless loop if you enter an invalid number because the invalid token is still left on the stream, and nextInt() keeps trying over and over again to grab it.
You will have to get the data off the stream.
One thing you could do is use nextLine() instead, then explicitly try and parse the returned String into an integer (e.g. with Integer.parseInt()).
Another thing you could do is call input.next() (or input.nextLine()) in the exception handler, to read (and discard) the garbage input. You may have to tweak the Scanner delimiters to get next() to work for you if it's not meeting your requirements with default settings.

Related

Preventing the user from entering identical elements(within a malfunctioning try catch)

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.

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.

try/catch infinite loop? [duplicate]

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

Java Scanner strange behavior

I have a java scanner and two loops to handle user input, However it throws an NoSuchElement exception the second it hits the first loop with out asking for any input from the user.
Scanner Guess_input = new Scanner( System.in );
while (guess > 0){
failure = true;
while(failure)
{
System.out.println("Please input");
try
{
if (Guess_input.nextLine().length() == 1 && guesses.size() >= 1) {
guesses.add(Guess_input.nextLine());
System.out.println("You guessed" + guesses.get(guesses.size()) + "");
}
else if (Guess_input.nextLine().length() == 0) {
System.err.println("ERROR:");
Guess_input.nextLine(); //Clean Buffer
failure = true;
}
else
{
System.err.println("ERROR");
Guess_input.nextLine(); //Clean Buffer
failure = true;
}
}
catch(InputMismatchException ime)
{
System.err.println("error");
}
finally
{
Guess_input.close();
}
}
}
From the java documentation, when using the next() method of the Scanner class, you'll get
NoSuchElementException - if no such tokens are available
Whenever you call the nextLine() method, you are supposed to enter a String. You should first store the result of nextLine() in local variable unless that's what you want.
Another problem is that your try catch finally is done in your while loop. It means that for each iteration, your finally bloc will be executed everytime, so you'll think that there is an exception, while might be none. Apply these changes
try {
while (guess > 0) {
while (.....) {
.....
}
}
} catch (...){
....
}
finally{ .... }
The errant statement is guesses.get(guesses.size()). In Java lists use zero-based indexes, i.e. the index of the first element is always 0 and the last element is size - 1. By definition the size of a list is an invalid index.
You probably should just hold the next line in its own variable before adding it to the list so that your sysout statement can just reference the variable instead of pulling the value back out of the list. But the easy solution is to just change the code to guesses.get(guesses.size() - 1)
You're calling guesses.nextLine() way too many times. Every call to nextLine() will block the app and expect input. Furthermore, theres other issues to worry about there... like other people pointed out.
I'll stick to the scanner though.

Categories

Resources