Infinite loop with java code, Scanner object buffer may be - java

I'm trying to read a number for a switch case option but I'm stuck with an exception. I will try to explain the problem better in code:
do{
try{
loop=false;
int op=teclado.nextInt();
//I tryed a teclado.nextLine() here cause i saw in other Q but didn't work
}
catch(InputMismatchException ex){
System.out.println("Invalid character. Try again.");
loop=true;//At the catch bolck i change the loop value
}
}while(loop);//When loop is true it instantly go to the catch part over and over again and never ask for an int again
When I type an int it works perfectly, but the exception makes it start over. The second time, the program does not ask for the int (I think it could be a buffer and I need something like fflush(stdin) in C), and the buffer just starts writing like crazy.

You would be well-served creating a new instance of Scanner from within the catch to get the input should you fail. EDIT: You can use a Scanner.nextLine() to advance past the newline character when you fail. A do...while loop may be inappropriate for this, since it guarantees that it will execute at least once.
A construct that may help you out more is a simple while loop. This is actually a while-true-break type of loop, which breaks on valid input.
while(true) {
try {
op=teclado.nextInt();
break;
} catch(InputMismatchException ex){
System.out.println("Invalid character. Try again.");
teclado.nextLine();
}
}

Related

Java prints repeatedly if try catch is used

I am making a basic application where it trains your math skills. I have this code:
while (true)
{
try
{
int userAnswer;
System.out.println("Type quit to exit to the menu!");
int randInt = r.nextInt(num2);
System.out.println(num1 + " + " + randInt + " =");
userAnswer = in.nextInt();
if(userAnswer == num1 + randInt) System.out.println("Correct!");
else System.out.println("Wrong!");
break;
}
catch(Exception e)
{
}
}
When someone prints out a d or something in the answer, the try catch goes. But, then it goes to the while loop and repeatedly spams Type quit to exit to the menu and then something like 1 + 2 = infinitely... I think I know what's wrong, userAnswer has been assigned already as something that throws an exception that goes to the catch and it just keeps printing those and goes to the catch and goes back because userAnswer is already assigned. I think this is what is happening, I could be wrong. Please help!
EDIT: I forgot to make this clear, but I want the question to be re-printed again, exiting out of the loop goes to a menu where you can't get the question back, I want it to redo what's in the try catch...
You should never catch an Exception without handling it.
catch(Exception e)
{
System.out.println("An error has occured");
break;
}
This should stop your program from looping infinitely if an Exception occurs.
If user input comes as letter it will get an exception because you are trying to read(parse) as integer. So your catch clause is in the loop you have to write break in there to go out from loop.
Still i will suggest you to getline as string and than compare with your cli commands (quit in your case) than you can try to parse it as an integer and handle loop logic.
You're not breaking the while loop if there is a mismatch
while(true)
{
try
{
}
catch(InputMisMatchException e)//I suggest you to use the exact exception to avoid others being ignored
{
System.out.println("Thank you!");
break;//breaks the while loop
}
}
Yoy're not breaking the loop in case of Exception occurs.
Add break; statement in the catch block to run your program without going to infinite loop, in case exception occurs.
Since the given answers don't match your requirement I'll solve that "riddle" for you.
I guess what you didn't knew is that the scanner won't read the next token if it doesn't match the expectation. So, if you call in.nextInt() and the next token is not a number, then the scanner will throw an InputMismatchException and keeps the reader position where it is. So if you try it again (due to the loop), then it will throw this exception again. To avoid this you have to consume the erroneous token:
catch (Exception e) {
// exception handling
in.next();
}
This will consume the bad token, so in.nextInt() can accept a new token. Also there is no need to add break here.
Mind that in.next() reads only one token, which is delimited by a whitespace. So if the user enters a b c, then your code will throw three exception and therefore generate three different question befor the user can enter a number. You can avoid that by using in.nextLine() instead. But this can lead into another problem: Scanner issue when using nextLine after nextXXX, so pay attention to that :).

Data Validation and Scanners in Java

I have a question regarding data validation and scanners.The following piece of code checks userinput.Anything other than an integer is not allowed and the user is asked to re-enter a value.My question is that the code works only if the scanner is declared within the while loop.The program executes infinitely if the scanner is declared outside.Why is that?Thanks.
int UserInp;
boolean dataType=false;
while(dataType==false)
{
Scanner sc=new Scanner(System.in);
try
{
System.out.print("\nEnter a number: ");
UserInp=sc.nextInt();
dataType=true;
}
catch(Exception JavaInputMismatch)
{
System.out.println("Option not available.Try again.");
}
}
Interesting problem!
What happens is that the Scanner attempts to translate the non-integer to an integer, and realizes it can't -- so it throws an InputMismatchException. However, it only advances past the token if the translation was successful.
Meaning, the invalid string is still in the input buffer, and it will fail the translation every single time you loop and try to call nextInt(). You never set dataType to true, and so you loop infinitely.
To see this in action, you can grab the arbitrary content in your catch block and print it out:
catch(Exception JavaInputMismatch){
System.out.println( sc.next() );
System.out.println("Option not available.Try again.");
}
Indeed, after invalid input, we get the following:
Enter a number: hello
hello
Option not available.Try again.
Enter a number:
And we don't loop infinitely. This is because the call to next() grabbed the value from the input buffer and advanced the scanner's pointer into that buffer to the next slot, which is now empty. So nextInt() will wait for input in that case.
Oh, and the reason it works fine if you initialize in the loop is that the scanner will always start reading input fresh; scanners don't share state across instances, so the "hello" that was in the buffer for the previous iteration isn't in the buffer for the next one due to the reinitialization.
Technically, it's still in the standard input buffer, but the scanner's pointer into that buffer is beyond the invalid string because it will start reading any new input, not existing input.
To add to Purag's answer, you could alternatively use nextLine() to advance the Scanner past the current line.
So your catch block will look like this:
catch(Exception JavaInputMismatch)
{
System.out.println("Option not available.Try again.");
sc.nextLine();
}
Tricky question.
You may get it!
The answer is simple. The Scanner object is kept live till the end of the execution as it is declared outside the while loop. Look this problem in the memory level.
The Scanner object is kept live so while entering the loop next time still the value(String value) will be there in Scanner object and it doesn't listens keyboard as the exception is already thrown.So the loop keeps going.
Note : The next() method in Scanner class will accept all the types of keyboard input but not the rest of the methods such as nextInt(), nextFloat() etc..,

Infinitive recursion when catching an Exception

Here is my code for inputting a student number:
When the user inputs the number in a unexpected format I will ask them to reinput by recursion. But it ends up with an infinitive recursion. Why?
private static int inputStudentNumber(){
System.out.println("Enter the student number:");
int studentNum;
try {
//Scanner in initialized before calling this method
studentNum = in.nextInt();
return studentNum;
} catch(Exception e) {
System.out.println("Invalid input, it can only be integer.");
return inputStudentNumber();
}
}
Take a closer look at the javadocs for Scanner.nextInt:
This method will throw InputMismatchException if the next token cannot be translated into a valid int value as described below. If the translation is successful, the scanner advances past the input that matched. (emphasis added)
If it's not successful, the scanner isn't advanced. That means that if you try to invoke nextInt() again, you'll be trying to get an int from the same token as before, and you'll once again get an InputMismatchException.
Your code basically says: try to read the next token as an int. If that fails, recurse to try to read the token as an int again. If that fails, recurse to try to read the token as an int again. If that fails... (and so on, until you get a StackOverflowException from too much recursion).
If you want to use recursion for this, you should probably use next() to skip to the next token. And only catch InputMismatchException, so that you won't also catch NoSuchElementException (which won't happen for System.in, but is good practice in general -- what if you later decide to read from a file, and that file has reached its end?).
} catch(InputMismatchException e) {
System.out.println("Invalid input, it can only be integer.");
in.next(); // skip this token
return inputStudentNumber();
}
An even better approach would be to avoid using the exception to control your logic in the first place. To do this, you'd have to know ahead of time whether nextInt will succeed. Luckily for you, hasNextInt() lets you do exactly that!
private static int inputStudentNumber() {
System.out.println("Enter the student number:");
if (in.hasNextInt()) {
return in.nextInt();
} else {
System.out.println("Invalid input, it can only be integer.");
in.next(); // consume the token
return inputStudentNumber();
}
}
The advantage here -- besides the general "don't use exceptions for control flow" advice -- is that the base case is super clear. If there's an int ready, that's your base case; if not, you have to advance the scanner and try again.
The problem is that if a non-integer is entered as input, then that input is not consumed by the scanner. So you just keep reading it.
You may want to just read the input as a string and then try to convert it separately.
Your problem is probably that in.nextInt() is throwing an Exception. A code smell that I see is that you use:
catch(Exception e) {
....
}
The best practice here is to only catch the specific Exception you are expecting, so it should be:
catch(InputMismatchException e) {
....
}
If you do this, then whatever in.nextInt() is throwing will properly propagate to the top, and you will probably see that in is not initialized or some such problem.
See here for the Exceptions that nextInt() can throw.
http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#nextInt()
try this...
private static int inputStudentNumber(){
System.out.println("Enter the student number:");
int studentNum;
int var = 1;
while(var ==1)ยด
{
try{
studentNum = in.nextInt();
var=0;
return studentNum;
}catch(Exception e){
System.out.println("Invalid input, it can only be integer.");
var=1;
return inputStudentNumber();
}
}
}

Infinite loop on one hand, NoSuchElementException on the other

I recently asked if there is any possible way whatsoever to get an exception from assigning a value to a String variable with the Scanner (The thread is here:)
And one of the guys told me that CTRL+D would be a case where a NoSuchElementException could be thrown. This to me is kind of a special case because input.nextLine() returns a String, and a String can be basically anything a user could type on the keyboard, so one would assume that input.nextLine() would not be a concern to throw an exception.
So I decided to add some try catch blocks into a program I'm writing on the off chance that CTRL+D is pressed when the program is asking for a number.
The problem I've run into is that when I catch the CTRL+D exception, the Scanner needs to be flushed, but if I flush the Scanner, it will cause a NoSuchElementException to occur because no new line exists. I'm using this all in a while true loop, so I'm kind of stuck between a rock and a hard place.
I will post one version of the code, with the input.nextLine() commented out. If you run it as is, you will get the infinite loop that happens when the Scanner needs to be flushed. If you uncomment the input.nextLine(), that very line of code will itself cause a NoSuchElementException.
import java.util.NoSuchElementException;
private int getMainOptions(){
System.out.printf("\n********** Main Options **********");
System.out.printf("\n*%32s*", "");
System.out.printf("\n* %-30s*", "[1] Create Customer");
System.out.printf("\n* %-30s*", "[2] Create Reservation");
System.out.printf("\n* %-30s*", "[3] Display Customer");
System.out.printf("\n* %-30s*", "[4] Display Reservation");
System.out.printf("\n*%32s*", "");
System.out.printf("\n**********************************");
while(true){
try{
System.out.print("\nChoose Option: ");
if(input.hasNextInt()){
return input.nextInt();
}
System.out.print("\nInvalid option");
input.nextLine();
continue;
}
catch(NoSuchElementException e){
System.out.print("\nAn exception occurred.");
//input.nextLine();
}
}
}
Apart from creating the Scanner inside the while loop and destoying it in the catch to be recreated in the next iteration, what can be done to solve this problem?
The code goes into an infinite loop when the input.nextLine() is commented out or when input.hasNextLine() is there to check because it is in a while(true) loop with nothing to stop it since input.nextInt() is not called. if(input.hasNextInt()) will not wait for an int, but simply skip the code inside the if statement if an int is not present as input.
Instead try this:
while(true){
try{
System.out.print("\nChoose Option: ");
String in=input.nextLine();
try{
int i=Integer.parseInt(in);
return i;
}catch(NumberFormatException ex)
{
System.out.print("\nInvalid option");
}
}
catch(NoSuchElementException e){
System.out.print("\nAn exception occurred.");
//input.nextLine();
}
}
}
I hope this helps and that I am understanding the question correctly
I'm not sure you fully grasp what happens when the user presses Ctrl-D. When that happens the standard input stream is closed. There is no way to reopen a closed stream. Even if you create a new Scanner and pass it in System.in it will still throw a NoSuchElementException.
As a Linux user if I press Ctrl-D in an interactive program, I expect the program to terminate. That is really all you can do at that point.

Try catch block causing infinite loop? [duplicate]

This question already has answers here:
try/catch with InputMismatchException creates infinite loop [duplicate]
(7 answers)
Closed 7 years ago.
I am writing a simple java console game. I use the scanner to read the input from the console. I am trying to verify that it I ask for an integer, I don't get an error if a letter is entered. I tried this:
boolean validResponce = false;
int choice = 0;
while (!validResponce)
{
try
{
choice = stdin.nextInt();
validResponce = true;
}
catch (java.util.InputMismatchException ex)
{
System.out.println("I did not understand what you said. Try again: ");
}
}
but it seems to create an infinite loop, just printing out the catch block. What am I doing wrong.
And yes, I am new to Java
nextInt() won't discard the mismatched output; the program will try to read it over and over again, failing each time. Use the hasNextInt() method to determine whether there's an int available to be read before calling nextInt().
Make sure that when you find something in the InputStream other than an integer you clear it with nextLine() because hasNextInt() also doesn't discard input, it just tests the next token in the input stream.
Try using
boolean isInValidResponse = true;
//then
while(isInValidResponse){
//makes more sense and is less confusing
try{
//let user know you are now asking for a number, don't just leave empty console
System.out.println("Please enter a number: ");
String lineEntered = stdin.nextLine(); //as suggested in accepted answer, it will allow you to exit console waiting for more integers from user
//test if user entered a number in that line
int number=Integer.parseInt(lineEntered);
System.out.println("You entered a number: "+number);
isInValidResponse = false;
}
//it tries to read integer from input, the exceptions should be either NumberFormatException, IOException or just Exception
catch (Exception e){
System.out.println("I did not understand what you said. Try again: ");
}
}
Because of common topic of avoiding negative conditionals https://blog.jetbrains.com/idea/2014/09/the-inspection-connection-issue-2/

Categories