How to find out which variable is throwing an exception? - java

I'm writing a program that culculates tip and total from bill and tip rate.
public void takeUserInput() {
Scanner sc = new Scanner(System.in);
double billAmount;
int tipRate;
try {
System.out.print("What is the bill? ");
billAmount = sc.nextDouble();
System.out.print("What is the tip percentage? ");
tipRate = sc.nextInt();
tc.calculate(billAmount, tipRate);
} catch (InputMismatchException e1) {
String errorMessage = "Please enter a valid number for the ";
// errorMessage += billAmount or
// errorMessage += tipRate ?
}
I'm looking for a way to find out which variable throws InputMismatchException, so I can add which variable name into variable errorMessage and print to the screen.

There are various simple ways to get there:
Call hasNextXxx() prior calling nextXxx().
If you go for one try/catch block per input, it is very clear within your catch block which variable caused the problem (you could then call a generic method with a specific error message to avoid code duplication)
You could use reference types for your variables; if you use Double / Integer instead of double / int ... you could check which of the two variables is still null
You put in a little boolean variable, like billAmountIsValid. Initially that variable is false, you turn it to true after the call to nextDouble(). Then you can easily check in your try block whether you got a valid billAmount.
After some more thinking: you really want a combination of 1 + 2: you see; when the users enters a correct billAmount; why would you want to forget about that value when the second value gives a bad second value? No - you should be looping for each variable, until you receive a valid input. And only then you start asking for the next value!

The variable isn't throwing the exception, the evaluation of the right hand side of the variable assignment is, and so there is no information in the exception to say which variable it was about to assign that to had it succeeded.
What you could consider instead is a new method that encompasses the prompting messages and retries:
billAmount = doubleFromUser(sc, "What is the bill? ", "bill");
Where doubleFromUser is:
static double doubleFromUser(Scanner sc, String prompt, String description){
while(true) { //until there is a successful input
try {
System.out.print(prompt); //move to before the loop if you do not want this repeated
return sc.nextDouble();
} catch (InputMismatchException e1) {
System.out.println("Please enter a valid number for the " + description);
}
}
}
You will need a different one for int and double, but if you have more prompts, you will save in the long run.

Related

check for numeric input java

I need to check a user is inputting a numeric value in java. I've been trying to use the hasNextDouble but am getting weird errors using the hasNextDouble method and am not certain this is the way to perform this check.
Please note I cannot use while loops or any other advanced method except if.
import java.util.Scanner;
import java.lang.Math;
public class CentimeterInch
{
public static void main (String [] args)
{
final int MAX=100, feet=12, meter=100;
final double inch=2.54;
Scanner scan = new Scanner (System.in);
System.out.println ("This program converts distances. ");
System.out.println ("Enter distance and unit (e.g. 37 1 or 100 2):");
double distance=scan.nextDouble();
if (!scan.hasNextDouble())
{
System.out.println ("please enter a numeric value");
distance=scan.nextDouble();
}
int unitType = scan.nextInt();
if (distance<0)
{
System.out.println ("Please enter a non negative distance");
}
....
I fixed the typo but its still not functioning, when I input for example "a" it crashes. To me it also doesnt make sense to call hasNextDouble after placing the value in the 'double distance' variable but I didn't find any other way yet.
I only have 1 double variable to check, the 'int' does not need validation.
EDIT:
I advance a bit. Now it displays the error before crashing. How do I make it not crash but take the variable again?
if(!scan.hasNextDouble())
System.out.println ("please enter a numeric value");
distance=scan.nextDouble();
Thank you!
Typos aside, you're invoking hasNextDouble after consuming nextDouble.
The easiest way to fetch both in one line is to:
if (scan.hasNextDouble()) {
// TODO something
double foo = scan.nextDouble(); // this consumes the first double
}
else { // TODO exit with error }
if (scan.hasNextDouble()) {
// TODO something else
double bar = scan.nextDouble(); // this consumes the second double
}
else { // TODO exit with error }
If you want it in two gos (i.e. user presses enter twice) you can consume scan.next() twice and use Double.parseDouble on both String, while catching a NumberFormatException for format errors.
It should be scan.hasNextDouble() with emphasis on Double.

Simple Java method returns 0 no matter the user input

This method is supposed to return the integer that the user enters as long as it is only an integer (not a String, float, etc.) and as long as that integer is one of the options in the given list of options. I want to use this method throughout my program whenever I give the user a list of options they need to choose from. These lists will have varying sizes thus I pass as an argument the maximum value (maxValue) that the user could possibly choose thus giving the method the size of the list.
//This method handles the players input and checks if the number entered is one of the options listed or not
public static int response(int maxValue){ //the parameter is the number of options in the particular list
response = new Scanner(System.in);
Boolean check = true;
while(check){
try{
int yesOrNo = response.nextInt();
if(yesOrNo > maxValue || yesOrNo <= 0){ //checks if the int entered does not exceed the list size or go below zero
System.out.println("I'm sorry, that number was not one of the options. Please reselect your choice.");
}else{
check = false;
}
}catch(Exception e){ //catches an exception when the user enters a string or anything but an int
System.out.println("Please only use digits to make a selection.");
response(maxValue);
}
}
return yesOrNo; //returns the user's response. Well, it is supposed to.
}
I am a beginner with regards to programming. I am learning Java through online tutorials and trial and error on dumb, little programs I make. I am working on a fun little text-adventure and am still in the beginning stages.
The trouble I'm having is because this method will only return 0. Isn't yesOrNo being assigned the integer that the user inputs through the scanner response? Why is it only returning 0?
Thank you for your responses. I understand now that I needed to declare my int yesOrNo outside of the try because it was out of scope, as you all put it, being declared within.
BUT a few mentioned 'there is a completely unnecessary function call in the catch block'. The only problem is if I remove it there is an infinite loop created with the System.out.println("Please only use digits to make your selection.") when the user inputs Strings or other non-int values.
Here is my updated code:
//This method handles the players input and checks if the number entered is one of the options listed or not
public static int response(int maxValue){ //the parameter is the number of options in the particular list
response = new Scanner(System.in);
Boolean check = true;
int yesOrNo = 0;
while(check){
try{
yesOrNo = response.nextInt();
if(yesOrNo > maxValue || yesOrNo <= 0){ //checks if the int entered does not exceed the list size or go below zero
System.out.println("I'm sorry, that number was not one of the options. Please reselect your choice.");
}else{
check = false;
}
}catch(Exception e){ //catches an exception when the user enters a string or anything but an int
System.out.println("Please only use digits to make a selection.");
response(maxValue);
}
}
return yesOrNo; //returns the user's response. Well, it is supposed to.
}
After reading other post before just asking another question I found many others facing the same issue. It was correct what some were saying that the infinite loop was created because when the Scanner encounters an error it doesn't remove the token of that error thus causing the while loop to read the same error over again infinitely. Here is what i read exactly:
"As per the javadoc for 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.'
That means that if the next token is not an int, it throws the InputMismatchException, but the token stays there. So on the next iteration of the loop, getAnswer.nextInt() reads the same token again and throws the exception again. What you need is to use it up. Add a getAnswer.next() inside your catch to consume the token, which is invalid and needs to be discarded."
So now that infinite loop problem is fixed :) Onto finding what else I need to learn. Thank you.
yesOrNo goes out of scope because you declared it within the try block. Move the declaration outside to where it is in scope when you return it.
Boolean check = true;
int yesOrNo;
yesOrNo you're returning is not same as
int yesOrNo = response.nextInt();
in your loop. The yesOrNo from the loop disappears (goes out of scope) at the closing } of try.
There has to be another int yesOrNo somewhere. Look for it.
The only this can compile is if yesOrNo is declared as a class or instance variable, unseen in this code snippet.
The declaration of yesOrNo that we do see is declared inside a try block, shadowing the yesOrNo being returned. But there's no reason for it to be a class or instance variable.
Remove it from the class declaration, and declare it locally, before the try block, so it's in scope when it's returned.
int yesOrNo = 0;
try{
yesOrNo = response.nextInt();
I see "int yesOrNo" inside while loop. The value read inside while loop scope is limited to that. Declare that variable outside and try.

Continually Validating Integers

I have a method I'm using to validate user-inputted values in a program. Whenever the user inputs a string into a JOptionPane, I call this method and pass in the inputted string, plus the maximum and minimum values I need their input to be between. First I check if the input is an integer by trying to parse the input string and catching exceptions, then I check if the integer is between the min and max. My problem is that if the user inputs another incorrect non-integer value after being prompted, I don't know how to check if the new value is correct or not. Here is the method, can anybody help?
int checkInput(String input, int min, int max) {
Boolean isInteger = false;
Boolean inputAccepted = false;
int userInput = 0; //will be set later
while (!isInteger) {
try
{
userInput = Integer.parseInt(input);
}
catch (NumberFormatException e)
{
userInput = Integer.parseInt(JOptionPane.showInputDialog("Please enter only integers between " + min + " and "+ max + "."));
isInteger = true; //the problem here is that it assumes the user inputted a correct value after being prompted... what if they enter another incorrect value?
}
}
while (!inputAccepted) {
if (userInput < min || userInput > max)
{
userInput = Integer.parseInt(JOptionPane.showInputDialog("Please enter only integers between " + min + " and "+ max + "."));
}
else
{
inputAccepted = true;
}
}
return userInput;
}
I believe the main problem is that you have a method whose job isn't simple and well-defined. It looks like you have a statement outside this method that inputs a number; but checkInput has two jobs: making sure the number is valid, and inputting more numbers until it is. This is a problem in two ways: your code that does the input is duplicated in two places, and you have a method whose responsibility isn't clear.
Instead, try writing a method that just checks whether the input is valid, and returns true or false. I'd change the name to isValidInput. The caller would then have a loop that would perform the input, make sure it's valid, and go back if it isn't.
Usually I wouldn't answer a question like this by pointing to flaws in your design. But I think that in this case, if you rethink your design, your question will answer itself. (That's often the case when you design things correctly--things fall into place.)
Your checkInput() function should throw its own exception if the input is not correct. Spliting the code into a validator and a parser would result in parsing the input twice.

Input Validation of a Floating Point Number (Inside a Try-Catch Block)

I've tried scouring Google and several sites such as this to find an answer to my question and I'm just not having any luck. I'm in a second-tier Java course in college, and I'm trying to figure out how to do input validation on a floating point number while using a try-catch block. The gist of the scenario is as such:
A driver will call the method promptForMotherHeight(), this method is supposed to pull in a user's entry as a floating point number. The issue is that with the try-catch block, if the Scanner detects a non-floating point number, it won't dump the data out of the scanner's buffer. This leads to an infinite loop. I've tinkered with adding a Scanner.next() inside my catch block, but any data entered after the first attempt will not validate properly (meaning that I can enter in something such as 5.55555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555 and it will accept this as a valid input).
Here's what I'm working with, code-wise (I've imported all the things I need to at the top of the class and motherHeight is a private float instance variable at the top of the class):
public void promptForMotherHeight()
{
String motherHeightPrompt = "Enter mother's height in inches: ";
String motherError1 = "Invalid entry. Must be positive.";
String motherError2 = "Invalid entry. Must be a decimal number.";
boolean valid = false;
do
{
System.out.print(motherHeightPrompt);
try
{
motherHeight = stdIn.nextFloat();
valid = true;
}
catch (InputMismatchException e)
{
System.out.println(motherError2);
stdIn.next();
}
} while(!valid);
}
Any pointers or hints as to how I can accomplish proper input validation would be much appreciated. Thanks
You could do the floating point number validation in the try-catch like this.
do {
System.out.print(motherHeightPrompt);
try {
motherHeight = Float.parseFloat(stdIn.nextLine()); // This will read the line and try to parse it to a floating value
valid = true;
} catch (NumberFormatException e) { // if it was not a valid float, you'll get this exception
System.out.println(motherError2);
// You need not have that extra stdIn.next()
// it loops again, prompting the user for another input
}
} while (!valid); // The loop ends when a valid float is got from the user

scanner.nextInt(), out of range avoidance?

I've finished a simple program that converts a decimal number to binary (32bit). I would like to implement some type of error message should the user enter in an overflow number (anything over 2147483647). I tried a if_else , loop, but quickly found out I couldn't even do that. So I messed with taking the input as a string, and then using some things like .valueOF() etc, and still can't seem to get around to the solution.
I don't see how I can compare any value to a >2147483648 if I can't store the value in the first place.
Here's the bare code I have for the getDecimal() method:
numberIn = scan.nextInt();
Edit:: After trying the try / catch method, running into a compile error of
"non-static method nextInt() cannot be referenced from a static context".
My code is below.
public void getDec()
{
System.out.println("\nPlease enter the number to wish to convert: ");
try{
numberIn = Scanner.nextInt();
}
catch (InputMismatchException e){
System.out.println("Invalid Input for a Decimal Value");
}
}
You can use Scanner.hasNextInt() method, which returns false, if the next token cannot be converted to an int. Then in the else block, you can read the input as string using Scanner.nextLine() and print it with an appropriate error message. Personally, I prefer this method :
if (scanner.hasNextInt()) {
a = scanner.nextInt();
} else {
// Can't read the input as int.
// Read it rather as String, and display the error message
String str = scanner.nextLine();
System.out.println(String.format("Invalid input: %s cannot be converted to an int.", str));
}
Another way to achieve this is of course, using try-catch block. Scanner#nextInt() method throws an InputMismatchException, when it can't convert the given input into an integer. So, you just need to handle InputMismatchException: -
try {
int a = scan.nextInt();
} catch (InputMismatchException e) {
System.out.println("Invalid argument for an int");
}
I suggest you surround that statement with a try/catch block for NumberFormatException.
Like so:
try {
numberIn = Integer.valueOf(scan.next());
}catch(NumberFormatException ex) {
System.out.println("Could not parse integer or integer out of range!");
}
use exceptions.. whenever a number is entered more than its storing capacity then exception will be raised
Refer docs.oracle.com/javase/tutorial/essential/exceptions/
You can user hasNextInt() method to make sure that there is an integer ready to be read.
try this :
long num=(long)scan.nextLong();
if (num > Integer.MAX_VALUE){
print error.
}
else
int x=(int)num;
or try catch:
try{
int number=scan.nextInt()
}
}catch(Exception ex){
print the error
}

Categories