Code not exiting while loop (trying to catch exceptions) [duplicate] - java

This question already has answers here:
Java Scanner exception handling
(4 answers)
Closed 7 years ago.
I have written the very simple code (n1 / n2 = sum) whilst trying to learn try / catch exception handling.
I have a do / while loop which is supposed to make x = 2 when run successfully. If not, x = 1, where the user input can be entered again.
The code compiles and runs but if I try, for example n1 = 10, n2 = stackoverflow, the prinln from the caught exception runs forever!
Why is the loop stuck?
Thanks in advance
import java.util.*;
public class ExceptionHandlingMain {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int x = 1; // x originally set to 1
do { // start of do loop
try {
System.out.println("Enter numerator: ");
int n1 = input.nextInt();
System.out.println("Enter divisor");
int n2 = input.nextInt();
int sum = n1 / n2;
System.out.println(n1 + " divided by " + n2 + " = " + sum);
x = 2;
// when the code is completed successfully, x = 2 and do / while loop exits
} catch (Exception e) {
System.out.println("You made a mistake, moron!");
}
} while (x == 1);
}
}

Add input.nextLine() in your catch block to clear the line read.

That's because you are pressing return key post entering the number.
I would suggest you add input.nextLine(); call, so you consume return key as well after reading your input from Scanner.
So with nextInt api, when you type like:
123<return key>
nextInt will just pick up 123 as a string and convert that to a number and leave return key part as is.

Thank you #barak manos (and others who replied)
adding
input.nextLine();
immediately after
System.out.println("You made a mistake, moron!");
clears the input stream and allows the user to enter new data.
cite:
Answer adapted from https://stackoverflow.com/a/24414457/4440127
User: user3580294

Related

Program loops when invalid character is entered [duplicate]

This question already has answers here:
How to handle infinite loop caused by invalid input (InputMismatchException) using Scanner
(5 answers)
Closed last month.
So I'm building a program which takes ints from user input. I have what seems to be a very straightforward try/catch block which, if the user doesn't enter an int, should repeat the block until they do. Here's the relevant part of the code:
import java.util.InputMismatchException;
import java.util.Scanner;
public class Except {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
boolean bError = true;
int n1 = 0, n2 = 0, nQuotient = 0;
do {
try {
System.out.println("Enter first num: ");
n1 = input.nextInt();
System.out.println("Enter second num: ");
n2 = input.nextInt();
nQuotient = n1/n2;
bError = false;
}
catch (Exception e) {
System.out.println("Error!");
}
} while (bError);
System.out.printf("%d/%d = %d",n1,n2, nQuotient);
}
}
If I enter a 0 for the second integer, then the try/catch does exactly what it's supposed to and makes me put it in again. But, if I have an InputMismatchException like by entering 5.5 for one of the numbers, it just shows my error message in an infinite loop. Why is this happening, and what can I do about it? (By the way, I have tried explicitly typing InputMismatchException as the argument to catch, but it didn't fix the problem.
You need to call next(); when you get the error. Also it is advisable to use hasNextInt()
catch (Exception e) {
System.out.println("Error!");
input.next();// Move to next other wise exception
}
Before reading integer value you need to make sure scanner has one. And you will not need exception handling like that.
Scanner scanner = new Scanner(System.in);
int n1 = 0, n2 = 0;
boolean bError = true;
while (bError) {
if (scanner.hasNextInt())
n1 = scanner.nextInt();
else {
scanner.next();
continue;
}
if (scanner.hasNextInt())
n2 = scanner.nextInt();
else {
scanner.next();
continue;
}
bError = false;
}
System.out.println(n1);
System.out.println(n2);
Javadoc of 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.
YOu can also try the following
do {
try {
System.out.println("Enter first num: ");
n1 = Integer.parseInt(input.next());
System.out.println("Enter second num: ");
n2 = Integer.parseInt(input.next());
nQuotient = n1/n2;
bError = false;
}
catch (Exception e) {
System.out.println("Error!");
input.reset();
}
} while (bError);
another option is to define Scanner input = new Scanner(System.in); inside the try block, this will create a new object each time you need to re-enter the values.
To follow debobroto das's answer you can also put after
input.reset();
input.next();
I had the same problem and when I tried this. It completely fixed it.
As the bError = false statement is never reached in the try block, and the statement is struck to the input taken, it keeps printing the error in infinite loop.
Try using it this way by using hasNextInt()
catch (Exception e) {
System.out.println("Error!");
input.hasNextInt();
}
Or try using nextLine() coupled with Integer.parseInt() for taking input....
Scanner scan = new Scanner(System.in);
int num1 = Integer.parseInt(scan.nextLine());
int num2 = Integer.parseInt(scan.nextLine());
To complement the AmitD answer:
Just copy/pasted your program and had this output:
Error!
Enter first num:
.... infinite times ....
As you can see, the instruction:
n1 = input.nextInt();
Is continuously throwing the Exception when your double number is entered, and that's because your stream is not cleared. To fix it, follow the AmitD answer.
#Limp, your answer is right, just use .nextLine() while reading the input. Sample code:
do {
try {
System.out.println("Enter first num: ");
n1 = Integer.parseInt(input.nextLine());
System.out.println("Enter second num: ");
n2 = Integer.parseInt(input.nextLine());
nQuotient = n1 / n2;
bError = false;
} catch (Exception e) {
System.out.println("Error!");
}
} while (bError);
System.out.printf("%d/%d = %d", n1, n2, nQuotient);
Read the description of why this problem was caused in the link below. Look for the answer I posted for the detail in this thread.
Java Homework user input issue
Ok, I will briefly describe it. When you read input using nextInt(), you just read the number part but the ENDLINE character was still on the stream. That was the main cause. Now look at the code above, all I did is read the whole line and parse it , it still throws the exception and work the way you were expecting it to work. Rest of your code works fine.

Java Sum of numbers until string is entered

i've just started java programming and was wondering on how to approach or solve this problem i'm faced with.
I have to write a program that asks a user for a number and continually sums the numbers inputted and print the result.
This program stops when the user enters "END"
I just can't seem to think of a solution to this problem, any help or guidance throughout this problem would be much appreciated and would really help me understand problems like this. This is the best i could do
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
while (true) {
System.out.print("Enter a number: ");
int x = scan.nextInt();
System.out.print("Enter a number: ");
int y = scan.nextInt();
int sum = x + y;
System.out.println("Sum is now: " + sum);
}
}
}
The output is supposed to look like this:
Enter a number: 5
Sum is now: 5
Enter a number: 10
Sum is now: 15
Enter a number: END
One solution would be to not use the Scanner#nextInt() method at all but instead utilize the Scanner#nextLine() method and confirm the entry of the numerical entry with the String#matches() method along with a small Regular Expression (RegEx) of "\d+". This expression checks to see if the entire string contains nothing but numerical digits. If it does then the matches() method returns true otherwise it returns false.
Scanner scan = new Scanner(System.in);
int sum = 0;
String val = "";
while (val.equals("")) {
System.out.print("Enter a number (END to quit): ");
val = scan.nextLine();
// Was the word 'end' in any letter case supplied?
if (val.equalsIgnoreCase("end")) {
// Yes, so break out of loop.
break;
}
// Was a string representation of a
// integer numerical value supplied?
else if (val.matches("\\-?\\+?\\d+")) {
// Yes, convert the string to integer and sum it.
sum += Integer.parseInt(val);
System.out.println("Sum is now: " + sum); // Display Sum
}
// No, inform User of Invalid entry
else {
System.err.println("Invalid number supplied! Try again...");
}
val = ""; // Clear val to continue looping
}
// Broken out of loop with the entry of 'End"
System.out.println("Application ENDED");
EDIT: Based on Comment:
Since since an integer can be signed (ie: -20) or unsigned (ie: 20) and the fact that an Integer can be prefixed with a + (ie: +20) which is the same as unsigned 20, the code snippet above takes this into consideration.
Do it like this:
public static void main(String[] args) throws Exception {
int sum = 0;
Scanner scan = new Scanner(System.in);
while (scan.hasNext()) {
System.out.print("Enter a number: ");
if (scan.hasNextInt())
sum += scan.nextInt();
else
break;
System.out.println("Sum is now: " + sum);
}
System.out.print("END");
}
This will end if the input is not a number (int).
As pointed out in the comments, if you want the program to stop when the user specifically enters "END", change the else-statement to:
else if (scanner.next().equals("END"))
break;

Java exception in thread "main"

I made a simple program which generates a random number between 1 to 100 and asks the user to enter a number between 1 and 100. If the number is more than the random number a message is displayed saying that it is more than the random number and if it is less it displays the opposite. The user only has 10 chances to guess the correct number. Here is the code:
import java.util.Scanner;
public class Program {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int random_num = (int) (Math.random() * 100) + 1;
System.out.println("guess a number between 1 and 100");
boolean isCorrect = false;
for (int i = 1; i <= 10; i++) {
int input = sc.nextInt();
if (input > random_num)
System.out.println("It is less than " + input);
else if (input < random_num)
System.out.println("It is more than " + input);
else {
isCorrect = true;
break;
}
}
if (isCorrect)
System.out.println("Congragulation you have guessd the correct number i.e " + random_num);
else
System.out.println("Game over it was " + random_num);
}
}
But I get errors here is the output:
guess a number between 1 and 100
It is more than 10
Exception in thread "main" java.util.NoSuchElementException
at java.base/ java.util.Scanner.throwFor(Scanner.java: 937)
at java.base/ java.util.Scanner.next(Scanner.java: 1594)
at java.base/ java.util.Scanner.nextInt(Scanner.java: 2258)
at java.base/ java.util.Scanner.nextInt(Scanner.java: 2212)
at Program.main(Program.java:15)
You are looping over the Scanner, but not checking if you have any input to fetch.
Here is an excerpt from the Java docs:
public int nextInt()
Scans the next token of the input as an int.
An invocation of this method of the form nextInt() behaves in exactly the same way as the invocation nextInt(radix), where radix is the default radix of this scanner.
Returns:
the int scanned from the input
Throws:
InputMismatchException - if the next token does not match the Integer regular expression,
or is out of range
NoSuchElementException - if input is exhausted
IllegalStateException - if this scanner is closed
Spot your error message ;)
Your code is valid for a standard Java environment.
However since you run the code in the SoloLearn Java container, you run into an error case that normally shouldn't happen.
Which is another thread already closed the input stream.
As Ivar already mentioned, you simply need to change your code to this to make it work on SoloLearn without errors:
for (int i = 1; i <= 10 && sc.hasNextInt(); i++) {
// Your logic
}
But since SoloLearn's implementation needs you to feed all of your input at once (different inputs seperated by a line break), you won't be able to run this correctly with different guesses.
SoloLearn will take those inputs, seperated by line breaks, and reads the different lines one at a time.
Then returns the inputs one at a time to your program.
Once it has no more input, it will close the stream.
However your program still tries to read this stream and then gets a java.util.NoSuchElementException error.
Here is reproducable code of the error with wath I believe happens behind the scenes at SoloLearn:
import java.io.ByteArrayInputStream;
import java.util.Scanner;
public class Program {
private String[] userInput;
private int inputNumber;
public Program(String input) {
this.userInput = input.split(" ");
this.inputNumber = 0;
}
public void startGame() {
int random_num = (int)(Math.random()*100)+1;
System.out.println("Guess the number between 1 and 100!");
boolean isCorrect = false;
for (int i = 1; i <= 10; i++) {
System.out.print("Guess "+ i +": ");
int input = getInput();
if (input > random_num)
System.out.println("It is less than " + input);
else if (input < random_num)
System.out.println("It is more than " + input);
else {
isCorrect = true;
break;
}
}
if(isCorrect)
System.out.println("Congratulations, you have guessed the correct number i.e " + random_num);
else
System.out.println("Game over! The number was " + random_num);
}
private int getInput() {
if (inputNumber < userInput.length)
fakeUserInput();
Scanner sc = new Scanner(System.in);
int input = -1;
input = sc.nextInt();
if (inputNumber == userInput.length)
sc.close();
return input;
}
private void fakeUserInput() {
System.setIn(new ByteArrayInputStream(userInput[inputNumber].getBytes()));
inputNumber++;
}
public static void main(String[] args) {
Program p = new Program("10 20 30");
p.startGame();
}
}
We feed it 3 guesses: 10, 20 and 30
And this is the output:
Guess the number between 1 and 100!
Guess 1: It is more than 10
Guess 2: It is more than 20
Guess 3: It is more than 30
Guess 4: Exception in thread "main" java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:873)
at java.util.Scanner.next(Scanner.java:1496)
at java.util.Scanner.nextInt(Scanner.java:2128)
at java.util.Scanner.nextInt(Scanner.java:2087)
at Program.getInput(Program.java:47)
at Program.startGame(Program.java:24)
at Program.main(Program.java:62)
As you can see, once the inputs are depleted and the stream is closed, we get this error.
I hope this explains your problem and sheds some light on the WHY.
here is answer, I try to do it and I found in main sc.close(). After comment line all work nice! :
#I_code Is this the actual code you are using? It works fine for me. That error is thrown when the the System.in is closed. Are you using sc.close() somewhere that you didn't show in the code?
– #Ivar Mar 15 '19 at 10:10
Good morning you need to initialize the input variable outside the for like this:
int input;
for (int i = 1; i <= 10; i++) {
input = sc.nextInt();
if (input > random_num)
Try this and tell me

do while loop with try catch [duplicate]

This question already has answers here:
Problem with "scopes" of variables in try catch blocks in Java
(3 answers)
Closed 6 years ago.
What is wrong with my code? I'm trying request prompt a user to enter a number if it is not between 1 and 6 or a number it should say invalid and prompt another try. The user may only have 3 tries.
import java.util.Scanner;
public class Game {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int[] numbers = new int[6];
System.out.println("Enter a number on a die from 1-6:");
String dieinput = input.next();
int invalidcount = 0;
System.out.println("Your number is: " + dieinput);
do{
try
{
// the String to int conversion
int dienum = Integer.parseInt(dieinput.trim());
int dienumOE = 0;
int count=0;
//test number input
if ((dienum >= 1) && (dienum<= 6))
System.out.println("number is " + dienum + oddoreven(dienum));
else
System.out.println("Invalid number, please enter a number 1-6");
count++;
System.out.println("Count" + count);
}
catch (NumberFormatException nfe){
System.out.println("Invalid number, please enter a number 1-6");
System.out.println("Count" + count);
}
while (count <= 3 && count >=0);
}
}
// Check if odd or even
public static String oddoreven(int num) {
String result;
if (num % 2 == 0)
result = "even";
else
result = "odd";
return result;
}
}
Your problem is "wrong" scoping: You can't use a variable within the catch block that is declared within the scope of the try block!
In other words; you need:
int counter = 0;
try { ...
} catch (...
if you want to use counter within both try and catch!
The "rule" is very simple: a variable is only visible up to that } that closes the "block" it is in.
That prevents you from actually compiling your code!
So, the real lesson here is more like: do not write 100 lines of code to then run the compiler. Only write as few lines as possible - every time when you think: this is "enough" to compile .. then compile. And then fix the errors reported to you. The java compiler is really good at giving you specific messages that tell you what you did wrong; but the more messy code you put up, the harder that gets!
And for the record: SO is not a "remote" compiler service that you should use to get your messy code to compile!

Prompt to continue while loop conflict

What seems fairly simple has got me completely confused. I ask the user for some inputs at the beginning of a while loop to be able to execute a program inside the loop. After the program is executed, I want to prompt the user at the end of the loop to restart or end the loop.
I am trying to make the loop ask only the LAST question after it has completed the program within it. Then, if the user has answered "yes", the loop will restart. Any other answer will result in ending the loop.
Here is my code
String rerun = null;
boolean run = true;
int x;
int y;
while (run = true)
{
// first question
x = keyboard.nextInt();
y = keyboard.nextInt();
// run program with x and y
// second question (ask to continue)
rerun = keyboard.nextLine();
if (rerun.equalsIgnoreCase("yes"))
{
continue;
}
else
{
run = false;
//break; stops the loop without answering the second question
}
}
Sample input/output:
Enter height and width of the house you want me to draw: 4 4
Program runs...
Bob, do you want me to draw another house for you (yes to continue)?
Enter height and width of the house you want me to draw (must be even numbers):
Why is it asking me the height and width again even though I have conditions at the end, prohibiting the loop to restart before I prompt it to continue?
Thank you!
Try this.
I haven't changed your code much, but I've printed a prompt on the screen before asking for a user input and printed the user input on the screen before restarting the loop. You could also do a try and catch block as below and see where the exception occurs. Also this would help in cause if a user enters a String instead of int for x or y.
import java.util.Scanner;
public class Test {
public static void main(String args[]) {
String rerun = null;
boolean run = true;
Scanner keyboard = new Scanner(System.in);
while (run == true) {
int x = 0;
int y = 0;
String val = "";
System.out.print("Enter x int : ");
try {
x = keyboard.nextInt();
}
catch (Exception ex) {
System.out.println("Error at x : " + ex.getMessage());
}
System.out.print("Enter x int : ");
try {
y = keyboard.nextInt();
}
catch (Exception ex) {
System.out.println("Error at y : " + ex.getMessage());
}
System.out.print("Enter string : ");
try {
val = keyboard.nextLine();
}
catch (Exception ex) {
System.out.println("Error at string: " + ex.getMessage());
}
System.out.println("x : " + x + ", y : " + y + ", val : " + val);
}
}
}
The problem is that after you use the nextInt() method the 'end of line' character is still in the input buffer. You must manually flush the buffer by calling nextLine(). I have modified your code below to show how you can fix this.
// first question
x = keyboard.nextInt();
y = keyboard.nextInt();
// run program with x and y
//Flush Input Buffer
keyboard.nextLine();
// second question (ask to continue)
rerun = keyboard.nextLine();
From your question it looks as though you want the loop to run at least once before the test. If that's the case then a do while loop is probably more appropriate than a while loop.
A do while loop looks something like:
do {
int x = keyboard.getInt();
int y = keyboard.getInt();
// process
System.out.println("Do you want to continue?");
} while (keyboard.nextLine().equalsIgnoreCase("yes"));
That seems to me to capture your intent better than the while loop of your original code and avoids having a keepRunning boolean (which I find confusing to read).
If you find the while statement confusing, rather than going back to a boolean variable, you can split the test into a separate method:
do {
...
} while (shouldRepeat());
private boolean shouldRepeat() {
System.out.println("Do you wish to continue?");
String answer = keyboard.nextLine();
return answer.equalsIgnoreCase("yes");
}
In my view that is still a clearer and less fragile solution than having a flag that is set.

Categories

Resources