Java Scanner strange behavior - java

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.

Related

What does happen inside this catch block?

I found this code online as a password loop game, it's working fine, but my question is: how?
What does happen in this catch block exactly?
I'm curious about this line specifically:
reader.next();
boolean loop = true;
Scanner reader = new Scanner(System.in);
System.out.println("PIN: ");
while (loop) {
try {
Integer Code = reader.nextInt();
if (Code == 8273) {
System.out.println("Access granted");
loop = false;
} else {
System.out.println("Access denied");
}
} catch (Exception e) {
System.out.println("Please enter a valid PIN!");
reader.next();
}
}
Edit : of course I did deliberately input a Non-integer input to cause the exception.
Edit2 :
When I removed that line, the program kept printing Please enter a valid PIN! For ever.
In fact, what the programmer really wanted here is to capture the next line of input, and verify whether that was a valid integer.
But the code is, admittedly, very confusing. And it relies on the fact that by default, when you "swallow" the next token with anything but .nextLine() with a Scanner, it relies on the current delimiter, which by default matches a newline.
Not good.
Here is a version which is more explicit:
String input;
int code;
while (true) {
System.out.print("PIN: ");
input = reader.nextLine();
try {
code = Integer.parseInt(input);
} catch (NumberFormatException ignored) {
// not an integer!
System.out.println("Enter a valid PIN!");
continue;
}
if (code == 8273)
break;
System.out.println("Access denied");
}
System.out.println("Access granted");
If nextInt throws an exception (because the value entered isn't an int), then the catch block is entered. The last line of which,
reader.next(); // <-- discards invalid token.
Removes the invalid token and then the loop iterates.
Also, don't box the Code1
int code = reader.nextInt();
1Using an Object type and then testing equality with == is a bad idea™. Also, by convention Java variable names start with a lower case letter.
The catch block simply catches the exception when anything other than an integer is entered. Since Code is an Integer, the input would have to be an integer. After catching the exception and printing the error, the reader moves to the next input until a proper value is entered, and the boolean loop becomes false, which ends the while loop at the end of the if statement once the correct value is entered.

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.

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.

For loop not a statement error

I'm trying to use for loops to check if a user is inputting an integer. The code will not let the user pass unless it is given an integer. I'm going to post a portion of my code, but if you think the error is outside of what I posted, I'll post the rest:
error:
not a statement
Code:
for (int prompt = 1; prompt < mainarray.length; prompt++) {
System.out.println("Please enter #" + prompt);
checkint = scan.nextInt();
// The error is pointing to the != in the following loop.
//I have check int declared above this code.
for (checkint != (int) checkint) {
System.out.println("This is not an integer, please input an integer");
}
mainarray[prompt] = checkint;
System.out.println("Number has been added\n");
}
You need an If statement to check this, not a for loop
if(checkint != (int)checkint)
{
System.out.println("This is not an integer, please input an integer");
}
Edit:
The Op said he/she is getting error as: java.util.InputMismatchException:null (in java.util.Scanner)
Solution:
You are using nextInt();. The java.util.Scanner.nextInt() method Scans the next token of the input as an int. if the next token does not match the Integer regular expression, or is out of range it will throw InputMismatchException.
You can use this code
Scanner scan = new Scanner(System.in);
String s = scan.nextLine();
try{
val = Integer.parseInt(s);
}
catch(NumberFormatException ex){
System.out.println("This is not an integer, please input an integer");
}
Even better,
try{
checkint = scan.nextInt();
}
catch(Exception ex){
System.out.println("This is not an integer, please input an integer");
}
Edit2
try
{
checkint = scan.nextInt();
mainarray[prompt]=checkint;
}
catch(Exception ex)
{
System.out.println("An integer is required;" + "input an integer please");
}
for(checkint != (int)checkint)
Isn't valid syntax for a for loop. That's a while loop. Consider this:
while (checkint != (int)checkint)
A while loop has one condition and will loop until that condition is not met. A for loop is actually just a while loop in disguise, but has three conditions:
starting point/initialization; condition; increment
However, you can leave the starting point and the increment blank to simulate a while loop.
HOWEVER this will put you in an ENDLESS LOOP. I don't know why you want a loop in the first place:
Finally, you should actually be doing this:
if (checkint != (int)checkint)
Change
for(checkint != (int)checkint)
as
for(;checkint != (int)checkint;)
From Doc
The general form of the for statement can be expressed as follows:
for (initialization; termination; increment) {
statement(s)
}
The initialization expression initializes the loop; it's executed
once, as the loop begins.
When the termination expression evaluates to false, the loop
terminates.
The increment expression is invoked after each iteration through the
loop; it is perfectly acceptable for this expression to increment or
decrement a value.
BUT this will leads to an infinite loop in your code. So change it as
if (checkint != (int)checkint)

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