Java - Try/Catch NumberFormatException uses a former value? - java

First post so my apologies if this was done incorrectly (and am also relatively new to programming, so any extraneous tips are also appreciated).
So I have written up a basic calculator program in Java. It works well currently, but I am having a particular issue with NumberFormatException. Here's the code:
private static double spaceTestAndConvert(String numInput){
Scanner input= new Scanner(System.in);
if (numInput.equalsIgnoreCase("quit")){
System.exit(1);
}
else if(numInput.equalsIgnoreCase("C/E")){
Restart();
}
try{
return Double.parseDouble(numInput.trim());
}
catch(NumberFormatException nfe){
numInput = "";
System.out.println("Please enter only one number without any spaces or letters: ");
numInput = input.nextLine();
spaceTestAndConvert(numInput.trim());
return Double.parseDouble(numInput.trim());
}
}
The issue is that after trying to force an error by entering in several inputs which would cause NumberFormatException and then entering in a valid input, the program will crash from a NumberFormatException citing the previous invalid input.
I.E. -
"1 2 3"
loops back
"1 2 q 3"
loops back
"12q3 3 sqw 1"
loops back
"12"
crash - Exception in thread "main" java.lang.NumberFormatException: For input string: "12q3 3 sqw 1"
It only occurs after several occurrences of the exception. I'm curious why it is doing this. Any advice on how to fix this or explanation of what is happening? If you need any other part of the code, please let me know! Thanks!

I don't follow everything that you're saying, but these 2 lines (from within your catch block) look problematic...
spaceTestAndConvert(numInput.trim());
return Double.parseDouble(numInput.trim());
You are calling the spaceTestAndConvert function recursively, but throwing away the value. I don't understand why you would call it and not be interested in the value.
The second line is also a mess. You so carefully surround the first call to Double.parseDouble() with try/catch, but then you call it again within your catch block. If the second Double.parseDouble() generates a NumberFormatException, it will not be caught.

removing the return in catch will solve your problem. because if you have return on it, you are going to return an invalid Number format since you are in a catch. What you want to do is to return a value when it is now valid, you are now actually doing it inside the try. Don't force your program to return the value with error (since it is in a catch) because it will really give you an error.
returning to previous method after you had the right value (because of recursion) will still have the stack of error value aside from success value you gained from the end part because they are different variables.
private static double spaceTestAndConvert(String numInput){
Scanner input= new Scanner(System.in);
if (numInput.equalsIgnoreCase("quit")){
System.exit(1);
}
else if(numInput.equalsIgnoreCase("C/E")){
Restart();
}
try{
return Double.parseDouble(numInput.trim());
}
catch(NumberFormatException nfe){
numInput = "";
System.out.println("Please enter only one number without any spaces or letters: ");
numInput = input.nextLine();
spaceTestAndConvert(numInput.trim());
}
}

Related

while loop parsing Double.IsNaN improperly

Language: Java, IDE: eclipse mars
The program is supposed to prompt the user (using JOptionPane) for a positive value. I'm trying to catch the invalid entries. My while statement catches the negative numbers but not the strings. When a negative number is entered, the prompt is shown again, but when a string value is entered, the exception is caught and the program moves on (when it should re prompt the user).
Once a positive value has been entered, the program assigns it to a value in another class. (We're learning the MVC OOP design pattern).
Double.isNaN(Double.parseDouble(h)) ---> can anyone help me find what am I missing?
// prompt to get bandwidth from user
// check for validity
// if invalid, prompt again
try{
h = JOptionPane.showInputDialog("Enter bandwidth as a positive number");
// loop until parsed string is a valid double
while (Double.isNaN(Double.parseDouble(h)) || Double.parseDouble(h) <=0) {
h = JOptionPane.showInputDialog("Enter bandwidth as a positive number");
}
// h has been set to valid double, set it to bandwidth
model.setBandwidth(Double.parseDouble(h));
}catch(NumberFormatException|NullPointerException NFE){
System.err.println("Caught exception: " + NFE.getMessage());
}
This is because of how parseDouble() works.
Throws:
NumberFormatException - if the string does not contain a parsable double.
(See here)
So if the String is not a double parseDouble() will not return NaN but throw an exception, which means your catch clause will be called.
To solve this problem maybe use recursively algorithm which will call your method again if an exception is thrown.
As 4castle already stated, you need to move your try/catch block inside your while loop.
However, for validating user input you can basically stick to the following pattern:
public Foo getUserInput() {
Foo result;
do {
try {
String s = requestUserInput(); // something like Scanner.nextLine()
result = parseUserInput(s); // something like Double.parseDouble(String)
}
catch(Exception exc) {
// maybe you want to tell the user what's happened here, too
continue;
}
}
while(!isValid(result)); // something like (0 < result)
return result;
}

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.

How do I ensure that Scanner hasNextInt() asks for new input?

New programmer here. This is probably a really basic question, but it's stumping me nevertheless.
What I'm trying to do is write a method that supplies only one integer input so I can use that input in my main program without having to mess around with non-integer inputs. However, even writing the method to do that in its own method seems to be problematic.
public static int goodInput () {
Scanner input = new Scanner (System.in); //construct scanner
boolean test = input.hasNextInt(); //set a sentinel value
while (test == false) { //enter a loop until I actually get an integer
System.out.println("Integers only please"); //tell user to give me an integer
test = input.hasNextInt(); //get new input, see if it's an integer
}
int finalInput = input.nextInt(); //once i have an integer, set it to a variable
input.close(); //closing scanner
return finalInput; //return my integer so I don't have to mess around with hasNextInt over there
}
This seems to be broken in multiple levels, but I'm not really sure why.
If I enter an integer value like 0 or 1 when I'm first asked for input, it should skip the loop entirely. But, instead, it enters the loop, and prints "Integers only please". Even worse, it doesn't actually ask for input while I'm in there, and just prints that line repeatedly.
I understand the latter problem is probably due to token issues, but I'm not necessarily sure how to solve them; closing and then reopening the scanner gets Eclipse to bug me over "duplicate objects", simply assigning the old input to a garbage String variable that is never used tells me that "No line was found" at runtime, and I'm not experienced enough to think of other ways to get new input.
Even once that's solved, I need to find some way to avoid entering the loop in the case of having an integer. I don't really understand why integer inputs inter the loop to begin with, so I'm not sure how this would be possible.
Please help? Sorry if this is an old question; tried looking at past questions but none of them seem to have the same problem that I have.
You were close: this works fine for me:
Scanner input = new Scanner(System.in); //construct scanner
while(!input.hasNextInt()) {
input.next(); // next input is not an int, so consume it and move on
}
int finalInput = input.nextInt();
input.close(); //closing scanner
System.out.println("finalInput: " + finalInput);
By calling input.next() in your while loop, you consume the non-integer content and try again, and again, until the next input is an int.
//while (test == false) { // Line #1
while (!test) { /* Better notation */ // Line #2
System.out.println("Integers only please"); // Line #3
test = input.hasNextInt(); // Line #4
} // Line #5
The problem is that in line #4 above, input.hasNextInt() only tests if an integer is inputted, and does not ask for a new integer. If the user inputs something other than an integer, hasNextInt() returns false and you cannot ask for nextInt(), because then an InputMismatchException is thrown, since the Scanner is still expecting an integer.
You must use next() instead of nextInt():
while (!input.hasNextInt()) {
input.next();
// That will 'consume' the result, but doesn't use it.
}
int result = input.nextInt();
input.close();
return result;

How to accept strings or integers in the same user input

I want to accept user input as either an integer or a string in Java but I always get an error no matter what I do.
My code is very simple (I'm a beginner):
System.out.println(
"Enter the row number (or enter e to quit the application):"
);
Scanner rowInput = new Scanner(System.in);
int row1 = rowInput.nextInt();
I want the user also to be able to press "e" to exit.
I have tried several things:
1) To convert row1 to a String and and say:
if((String)(row1).equals("e"){
System.out.println("You have quit") }
2) To convert "e" to an integer and say:
if(row1 == Integer.ParseInt("e"){
System.out.println("You have quit") }
3) To do the switch statement but it said I had incompatible types (String and an int).
My errors usually say: Exception in thread "main" java.util.InputMismatchException
Is there somebody who could help me?
Many thanks in advance!
You can try something like this
Scanner rowInput = new Scanner(System.in);
String inputStr = rowInput.nextLine();
try{
int row1 = Integer.parseInt(inputStr);
} catch (NumberFormatException e) //If exception occurred it means user has entered 'e'
{
if ("e".equals(inputStr)){
System.out.println("quiting application");
}
}
you should read the input from your scanner as String type and the try to convert that String input into integer using Integer.parseInt().
If its successful in parsing, it means user has input an Integer.
And If it fails, it will throw an exception NumberFormatException which will tell you that its not an Integer. So you can go ahead and check it for e if it is, do whatever you want as per your requirement.
You can't use nextInt() if you aren't sure that you will have a number coming in. Also, you can't parse e as an integer, because it is not an integer, it's either char or string (I'll suggest string in this case).
That means, your code should look like:
System.out.println("Enter the row number (or enter e to quit the application):");
Scanner rowInput = new Scanner(System.in);
string row1 = rowInput.next();
Then you have the data in a string. You can simply check if the string is e:
if (row1.Equals("e")) ...
It is also a good idea to check if the input is actually an integer then. Good way to check it is described here:
How to check if a String is numeric in Java
1) you should say Integer.parseInt() instead of Integer.ParseInt()
2) if you pass "e" to Integer.parseInt() you'll get java.lang.NumberFormatException
3) get your input as a string this way (cause it's safer)*:
Scanner rowInput = new Scanner(System.in);
String row = rowInput.next();
if (row.equals("e")) {
//do whatever
}
else if(row.matches("\\d+$")) {
//do whatever
}
*In your approach if user enters a non-integer input you'll encounter java.util.InputMismatchException
I have tried several things ....
Attempting to solve this problem by "trying things" is the wrong approach.
The correct approach is to understand what is going on, and then modify your solution to take this into account.
The problem you have is that you have a line of input that could be either a number or the special value e which means quit. (And in fact, it could be a couple of other things too ... but I will come to that.)
When you attempt to either:
call Scanner.nextInt() when the next input is not an integer, OR
call Integer.parseInt(...) on a String that is not an integer
you will get an exception. So what do you do?
One way is to change what you are doing so that you don't make those calls in those situations. For example:
call Scanner.hasInt() to see if the next token is an integer before calling nextInt(), or
test for the "e" case before you attempt to convert the String to an integer.
Another way to deal with this is to catch the exception. For example, you could do something like this:
String s = ...
try {
number = Integer.parseInt(s);
} catch (NumberFormatException ex) {
if (s.equals("e")) {
...
}
}
Either way will work, but I'm going to leave you to work out the details.
But the real point I'm trying to make is that the right way to solve this is to understand what is happening in your original version / versions, and based on your understanding, modify what you were doing. If you just randomly "try" alternatives that you found with Google, you won't progress to the point of being a productive programmer.
I said there were other cases. They are:
The user types something that is neither a number of your special e character. It could be anything. An empty line, hi mum ...
The user types the "end of file" character; e.g. CTRL-D on Linux or CTRL-Z on windows.
If you want your program to be robust you need to deal with these cases too.
Try this:
public class Demo{
public static void main(String[] args) {
Scanner s=new Scanner(System.in);
String choice = null;
System.out.println("Enter e to exit or some other key to stay:");
choice=s.next();
if(choice.equals("e"))
{
System.out.println("quits");
System.exit(0);
}
else
{
System.out.println("stays");
}
}
}
You can't convert a string into integer, use char ASCII codes instead.

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