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

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.

Related

Keep on prompting user after invalid input

Now I know that there is a thread called "Validating input using java.util.Scanner". I already looked there and that thread only answered 1/2 of my problems. The other half is when someone enters a number greater than 2 I get Array Index Out of Bounds Exception. I just need help on if someone enters a 3 for either row or column, the console should prompt something like this:
"Enter the coordinates to place an 'X'. Row then Column."
//enters 3 and 3
"Please enter a valid input"
It would keep and asking the user for a valid number until he gives one.
Would I need to do something like the !keyboard.hasNextInt() but for integers? And that would run smoothly with the rest of my code?
You could use a do-while loop. Something like
do {
//prompt
//input
} while (input not valid);
Where prompt and input should be replaced by code to prompt the user and accept input. In the while section, check if input is valid.
You're question isn't too clear but I'll try to make sense of it.
I'm assuming you've named your scanner "keyboard"
Before I try running this code, the first problem I can see is this (Note that I grabbed this from your code before you edited the question):
while (board[row][col] != ' ')
{
System.out.println("Already occupied space");
System.out.println("Choose again");
row = keyboard.nextInt();
col = keyboard.nextInt();
}
Earlier, you made sure that the user enters integers. However, you have abandoned that completely in this case.
Assuming you're trying to avoid an error if the user enters something other than an integer, this is what I would do:
while(true){
boolean valid = true;
if(!keyboard.hasNextInt()){
valid = false;
keyboard.next();
}
else{
row = keyboard.nextInt();
}
if(!keyboard.hasNextInt()){
valid = false;
keyboard.next();
}
else{
col = keyboard.nextInt();
}
if (valid && (row > 2 || col > 2)){
System.out.println("Please enter a valid input");
continue;
}
else if(!valid){
System.out.println("Please enter a valid input");
continue;
}
else
break;
}
There are a couple reasons this code might seem a bit long. First off, we're trying to test if the input is an integer before we attempt to store it as an int. Secondly, we want to compare the input after we store it successfully to see if it's less than 3. If the input isn't an integer, the boolean "valid" will be false. The way a compiler works, if valid is false in the if statement it will ignore anything to the right of the &&, avoiding an error.
I admit, this is using some commands that I haven't learned before, so this might not be the most efficient way. But you get the idea :)
P.S. You should probably throw the above code into a method.

Is there difference if I call input.nextLine() as part of exception catching in every catch block or inside a final block at the end of try-catch?

For example, here I put it only once, but I know that I can put it several times. What is the difference?
try{
if(tasks.size() <= 0){
System.out.println("Nothing to remove, no tasks");
}
else{
System.out.println("Enter index of task to remove");
int index = input.nextInt();
input.nextLine();
tasks.remove(index);
}
}
catch(InputMismatchException ex){
System.out.println("Please enter only numbers");
}
catch(IndexOutOfBoundsException ex){
System.out.println("Invalid index number");
}
}
finally will be called always, regardless if you cough exception or not so yes, there is a difference.
Anyway assuming you are using Scanner you should avoid using try-catch as part of your logic (they should be used only if exceptional situations happen since creating exception may be expensive). Instead try to prevent throwing exceptions with little help of hasNextInt method.
So you can try with something like:
System.out.println("Enter index of task to remove");
while (!input.hasNextInt()){
System.out.println("That was not proper integer, please try again");
input.next();// to let Scanner move to analysing another value from user
// we need to consume that incorrect value. We can also use
// nextLine() if you want to consume entire line of
// incorrect values like "foo bar baz"
}
//here we are sure that inserted value was correct
int int index = input.nextInt();
input.nextLine();// move cursor after line separator so we can correctly read
// next lines (more info at http://stackoverflow.com/q/13102045/1393766)
The difference is clarity and simplicity.
The finally block will always execute, if present. Code which is common to the entire block can be located there. In the future if a different response is required it can be changed in a single location.
When common code is spread out in multiple locations you run the risk of changing some but not all instances which can result in unexpected failures.

Is there another way of ignoring values using a while(true) loop besides using 'continue'?

I've been asked to get user input and ignore values that don't fall within the range of -30 and 40. To skip over invalid numbers I use a 'continue' statement. I've googled sources saying continue / break are bad practice. The IDE is also throwing an "unnecessary continue" warning. Is the code below good practice in solving this problem, should I just override the warning or address it?
My code is as shown below:
public class Temperatures
{
#SuppressWarnings("UnnecessaryContinue")
public static void main(String[] args) {
Scanner reader = new Scanner(System.in);
// Write your code here.
while(true)
{
//ask user for input
double userInput = Double.parseDouble(reader.nextLine());
//makes sure temperature is within range, if it isn't ignores value and moves on
if (userInput < -30.0 || userInput > 40.0)
{
continue;
}
//adds value to graph
else
{
Graph.addNumber(userInput);
}
}
}
Possibly the IDE is showing the warning because if you removed the continue your code would work exactly the same. Think about it.
The IDE is also throwing an "unnecessary continue" warning.
It is an unnecessary continue. Why?
If your if statement turns true, else would not be executed. If the if condition is false, else would be executed. Hence, there is no need of a continue here.
continue should have been used if:
while(true)
{
double userInput = Double.parseDouble(reader.nextLine());
if (userInput < -30.0 || userInput > 40.0)
{
continue;
}
Graph.addNumber(userInput);
}
There is no else statement, hence now you have to use a continue to skip the further execution of the current iteration.
You don't need to use continue in your case. Use this instead:
if( userInput >= -30 && userInput <= 40){
Graph.addNumber(userInput);
}

Error handling reading ints from Scanner in while loop

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.

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

Categories

Resources