Java: Program crashes after inputting two bad values - java

I coded a program, that calculates the gcd (greatest common divisor) and lcm (least common multiple). Everything works fine except the try {...} catch(...) {...}. Here is the part of the code that doesn't work as I want it to:
try {
num1 = Integer.parseInt(sc.nextLine());
}
catch(Exception e) {
System.out.println("Your input is not an integer (number w/o decimals)! Try again.");
System.out.print("Enter your first number: ");
num1 = Integer.parseInt(sc.nextLine());
}
When I input e.g. letters, it says:
Your input is not an integer (number w/o decimals)! Try again.
Enter your first number:
But when I type letters the second time, the program crashes:
Exception in thread "main" java.lang.NumberFormatException: For input string: "asdf"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
at java.base/java.lang.Integer.parseInt(Integer.java:658)
at java.base/java.lang.Integer.parseInt(Integer.java:776)
at GCDLCMgetter.main(GCDLCMgetter.java:56)
It is probably a very simple mistake I made but I can't figure it out...
Thank you

Your second parseInt method call is not in try catch block. You need to use a loop for this kind of logic.

It's because your second prompt is inside the catch block. Instead of prompting again inside the catch block, you want to wrap the entire code section in a loop so it comes back around to the try block for the prompt again.
Something like:
boolean repeat = true;
while(repeat){
try{
//Prompt for input
repeat = false;
}catch(Exception e) {
//Display error message
}
}

When the first time you give letters it goes into catch block. Displays the error message. And then executes the line num1 = Integer.parseInt(sc.nextLine());
Again you have entered the letters, but this time there is no try-catch block to handle this. So it throws error.

In your code, it gets executed twice:
Reads a Line at try{...}
There is an Exception
The Exception is handled by the catch(Exception e){...}
The num1 = Integer.parseInt(sc.nextLine()); inside the catch(Exception e){...} cannot be handled. It's not placed inside try{}.
Execution finished because the last exception cannot be handled by any catch.
It seems you're using Scanner, I would recommend you using a loop whis way:
while (sc.hasNextLine()){
try {
System.out.print("Enter your first number: ");
num1 = Integer.parseInt(sc.nextLine());
}
catch(Exception e) {
System.out.println("Your input is not an integer (number w/o decimals)! Try again.");
}
}
If you're managing integers, it would be interesting using Scanner.nextInt()
while (sc.hasNextInt()){
try {
System.out.print("Enter your first number: ");
num1 = sc.nextInt());
}
catch(Exception e) {
System.out.println("Your input is not an integer (number w/o decimals)! Try again.");
}
}

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.

Try block starts printing while printStackTrace method is Printing

public class Argon {
public static void main(String[] args) {
Basil basil = new Basil();
Scanner in = new Scanner(System.in);
do {
try {
System.out.println("Please enter a number!");
String num1 = in.nextLine();
System.out.println("Please enter another number!");
String num2 = in.nextLine();
basil.numberCruncher(num1, num2);
System.out.println(basil.getSum());
break;
} catch (NumberException e) {
e.printStackTrace();
}
} while (true);
}
}
The code above works tries a block of code and catches any errors that occur. I purposefully supplied an error and the code prints the following.
Please enter a number!
nop
Please enter another number!
w
NumberException: Your Program Went Bananas.
Please enter a number!
at Basil.numberCruncher(Basil.java:23)
at Argon.main(Argon.java:15)
The Stack Trace has not been fully printed, but the try block starts executing anyways.
Why does this occur and what could I do to fix it?
Throwable#printStackTrace prints to System.err by default. You're printing to System.out. Since there's only one console, it receives both of those streams.
Whatever controls the console you see must be doing its own buffering and flushing which does not synchronize the writes from each stream and that can cause mixed output even though the program executed sequentially.

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 and user input

This is a question for a homework assignment involving a try/catch block. For a try/catch I know that you place the code you want to test in the try block and then the code you want to happen in response to an exception in the catch block but how can i use it in this particular case?
The user enters a number which is stored in userIn but if he enters a letter or anything besides a number I want to catch it. The user entered number will be used in a switch statement after the try/catch.
Scanner in = new Scanner(System.in);
try{
int userIn = in.nextInt();
}
catch (InputMismatchException a){
System.out.print("Problem");
}
switch(userIn){...
When I try to compile, it returns symbol not found, for the line number corresponding to the beginning of the switch statement, switch(userIn){. A few searches later I find that userIn cannot be seen outside the try block and this may be causing the error. How can I test userIn for correct input as well as have the switch statement see userIn after the try/catch?
The int userIn is inside the try-catch scope, and you can use it only inside the scope not outside.
You must declare it outside the try-catch brackets:
int userIn = 0;
try{
userIn = ....
}.....
Use something like:
Scanner in = new Scanner(System.in);
int userIn = -1;
try {
userIn = in.nextInt();
}
catch (InputMismatchException a) {
System.out.print("Problem");
}
switch(userIn){
case -1:
//You didn't have a valid input
break;
By having something like -1 as the default value (it can be anything that you won't receive as input in the normal run, you can check if you had an exception or not. If all ints are valid, then use a boolean flag which you can set in the try-catch blocks.
Try something like this
int userIn = x; // where x could be some value that you're expecting the user will not enter it, you could Integer.MAX_VALUE
try{
userIn = Integer.parseInt(in.next());
}
catch (NumberFormatException a){
System.out.print("Problem");
}
This will cause and exception if the user entered anything than numbers because it will try to parse the user input String as a number

Scanner.reset() doesn't work

This piece of code is supposed to get an integer number from user and then finish the program. If the user inputs an invalid number, it asks user again.
After catching exception, it uses Scanner.reset() to reset the scanner, but it doesn't work. and it re-throws previous exception.
Scanner in = new Scanner(System.in);
while (true) {
try {
System.out.print("Enter an integer number: ");
long i = in.nextLong();
System.out.print("Thanks, you entered: ");
System.out.println(i);
break;
} catch (InputMismatchException ex) {
System.out.println("Error in your input");
in.reset(); // <----------------------------- [The reset is here]
}
}
I thought Scanner.reset() will reset everything and forget the exception. I put it before asking the user for a new input.
If I get the point wrong, what is the right way?
You misunderstood the purpose of the reset method: it is there to reset the "metadata" associated with the scanner - its whitespace, delimiter characters, and so on. It does not change the state of its input, so it would not achieve what you are looking for.
What you need is a call of next(), which reads and discards any String from the Scanner:
try {
System.out.print("Enter an integer number: ");
long i = in.nextLong();
System.out.print("Thanks, you entered: ");
System.out.println(i);
break;
} catch (InputMismatchException ex) {
System.out.println("Error in your input");
in.next(); // Read and discard whatever string the user has entered
}
Relying upon exceptions to catch exceptional situations is OK, but an even better approach to the same issue would be using has... methods before calling the next... methods, like this:
System.out.print("Enter an integer number: ");
if (!in.hasNextLong()) {
in.next();
continue;
}
long i = in.nextLong();
System.out.print("Thanks, you entered: ");
System.out.println(i);
break;
Per Scanner.reset() javadoc, the method only "resets" locale, radix and delimiter settings. It does not do anything to the data it already read.

Categories

Resources