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

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

Related

How to find out which variable is throwing an exception?

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.

Using Nested Scanners to Check for Blank Inputs, but [Return] key must be pressed twice

This question serves as a follow-up to a previous question.
I am trying to create a program that converts from one currency to another.
First, I'll post and explain the relevant code, then describe the desired outcome and some problems I came across.
do {
try {
invalidInput = false;
String line = input.nextLine();
Scanner lineScan = new Scanner(line);
BigDecimal moneyInput = lineScan.nextBigDecimal();
// second do-while loop that tries to emulate the outermost do-while loop
// introduces a second set of nested scanners
// re-prompts user for valid currency if they try a blank input
do {
try {
String line2 = input.nextLine();
Scanner lineScan2 = new Scanner(line2);
String currency = lineScan2.next();
if (currency.equals("USD")) {
// convert USD to CNY
} else if (currency.equals("CNY")) {
// convert CNY to USD
}
} catch (NoSuchElementException e) {
invalidInput = true;
System.err.print("Please enter a valid CURRENCY: "); // prompts user for currency ONLY
}
} while (invalidInput);
} catch (NoSuchElementException e) {
invalidInput = true;
System.err.print("Please enter the VALUE followed by the CURRENCY: ");
}
} while (invalidInput);
The outer do-while loop runs as long as invalidInput is true. At the beginning of the first try block, invalidInput is false, and it remains false unless the user enters an invalid input (e.g. blank input or non-numeric). Here, invalidInput becomes true, and the program loops back to the top of the try block after re-prompting the user for both moneyInput and currency.
Next, I wanted to find someway to check the validity of moneyInput and currency separately. The first set of nested Scanners is meant to process moneyInput. If the user inputs something invalid, it will re-prompt the user Please enter the VALUE followed by the CURRENCY:, and it will continue to do so until something valid is entered.
I then wanted to add the exact same functionality to check currency exclusively. This is the intended purpose of the second set of nested scanners (lineScan2). If a valid input is entered for moneyInput but not for currency, e.g. 100.00 abc, I'd like the program to retain the value of moneyInput, re-prompt the user for only currency, and continue to do so until a valid currency is entered (including if the user enters a blank input).
Here are some problems I'm running into:
The program is only reading moneyInput in the first line, instead of reading both moneyInput and currency. Secondly, for each input, the user must press [return] twice (note each of the empty lines in between each input).
The program also terminates inconsistently. In the image example above, after it finally accepts a valid moneyInput and currency and converts the value, the program does not terminate. It terminates prematurely if the moneyInput is entered first, followed by an invalid currency on a second line, like so:
But here, it terminates properly after a successful run (although this still isn't exactly right because it only is "successful" if moneyInput and currency are input on separate lines; ideally, the user should be able to enter both on the same line and the program prints the appropriate conversion):
However, one thing the program does do well is responding repeatedly to invalid (specifically, blank inputs):
And actually, in the case above, aside from the fact that [return] had to be entered twice when prompting for moneyInput and that it didn't terminate after a successful run, everything is working exactly as desired:
the user gets to try repeatedly until a valid input, and in the case
where moneyInput is valid but currency is not, the user only has
to enter a valid input for currency (i.e. they don't have to
re-enter moneyInput when only the currency was invalid).
So overall I am looking for ways to modify the code above to achieve the desired results. As mentioned in the comment section of the linked question at the very top of this post, another method I tried was another do-while loop inside (in place of the inner do-while loop) to check currency, and this worked except for when a blank input was entered, which is basically problem I had at the beginning of that post (here is my code: pastebin.com/raw/CT0qjBPk and example screenshots: imgur.com/a/mjfaL).
Sorry if this post is excessively specific and lengthy. I am a beginner programmer and trying to study Java as thoroughly as possible, and this process of improving code has been of great educational value. Thanks so much for reading and providing feedback.
Your implementation is overly-complex because you're using input in several different places. Here's essentially the pattern I suggested in my answer to your previous question:
try (Scanner in = new Scanner(System.in)) {
while (in.hasNextLine()) {
String line = in.nextLine();
doSomethingWithALineOfInput(line);
}
}
Here's roughly what your code is doing:
boolean invalidInput = false;
try (Scanner in = new Scanner(System.in)) {
while (in.hasNextLine()) {
do {
String line = input.nextLine();
invalidInput |= doSomethingWithALineOfInput(line);
do {
String line2 = input.nextLine();
invalidInput |= doSomethingWithASecondLineOfInput(line2);
} while (invalidInput);
} while (invalidInput);
}
}
Notice in particular that you're calling input.nextLine() in two separate places, which makes your code hard to reason about. One of the primary goals when programming is to reduce your problem into smaller subproblems - interleaving input.nextLine() calls everywhere (let alone inside nested do-while loops) forces you to continue dealing with one big problem.
So instead of mixing your line-processing and your token-processing code together, isolate them from each other. The only thing that should interact with input is the very outer while loop. Once you've read a line you're done with input for the remainder of that iteration.
Consider something like this (notice the use of a class to contain the values as we read them in):
class PromptForMoney {
private BigDecimal amount;
private String currency;
public void prompt(Scanner in) {
System.out.print("Enter an amount of money and currency to convert: ");
while (in.hasNextLine()) {
try {
processLine(in.nextLine());
return;
} catch (InputMismatchException | NoSuchElementException e) {
// we use the exception message to describe the problem to the user
// if Scanner generates exceptions with unclear messages you can
// catch them in processLine() and throw your own with a better message.
System.out.print("Invalid input - " + e.getMessage() + ": ");
}
}
throw new NoSuchElementException(
"No more input to read, but a valid amount or currency was not entered.");
}
private void processLine(String line) {
Scanner lineScanner = new Scanner(line);
if (amount == null) {
// this line will raise an exception if the line is empty
// or if it doesn't start with numerical token
amount = lineScanner.nextBigDecimal();
}
if (currency == null) {
// this line will raise an exception if the user didn't specify a currency
String c = lineScanner.next();
if (isValidCurrency(c)) {
currency = c;
} else {
throw new InputMismatchException(c + " is not a valid currency");
}
}
// if we get this far without raising an exception we've read a valid
// amount and currency from the user.
}
}
Notice how prompt() deals solely with lines, and processLine() deals solely with the contents of a single line. This cleanly separates the problem into smaller, easier-to-reason-about parts.
You'd use PromptForMoney like so:
public static void main(String[] args) throws IOException {
PromptForMoney prompt = new PromptForMoney();
try (Scanner in = new Scanner(System.in)) {
prompt.prompt(in);
}
System.out.println(convert(prompt.getAmount(), prompt.getCurrency());
}
There's another separation of concerns - only main() is responsible for directly interacting with System.in. As far as PromptForMoney is concerned its Scanner could be backed by a string or a file and it would work exactly the same.
Caveat: there are some best practices I'm not emphasizing for the sake of space and simplicity (e.g. preferring final instance variables). If you're interested in improving your code quality even further I strongly suggest reading Effective Java which goes into great detail about Java design patterns.

Checking if user entered anything?

I am trying to check if a user entered a number and if not, then it uses a default number like 10. How do i check if the user just presses enter and doesn't enter anything in Java
input = scanner.nextInt();
pseudo code:
if(input == user just presses enter without entering anything){
input = 10;
}
else just proceed with input = what user entered
//scanner is a Scanner
int i; // declare it before the block
try {
i = scanner.nextInt();
}
catch (InputMismatchException ime) {
i = 10;
}
// i is some integer from the user, or 10
First things first, geeeeeez guys, when the OP says something like
"I don't want an exception, i want i = 10 if nothing is entered, so what do i do"
That should clue you in that he probably doesn't know too much about exceptions (maybe even java) and might need a simple answer. And if that's not possible, explain to him the difficult ones.
Alright, here's the plain and simple way to do it
String check;
int input = 10;
check = scanner.nextLine/*Int*/();
if(check.equals(""))
{
//do nothing since input already equals 10
}
else
{
input = Integer.parseInt(check);
}
Let me explain what this code is doing. You were originally using nextInt() to get your number for input, correct? The problem is, nextInt() only responds if the user actually inputs something, not if they press enter. In order to check for enter, we used a method that actually responds when the user presses enter and used that to ensure that our code does what we wanted to. One thing I recommend using is an API, Java has one.
Here's the link for the API HERE
And here's the link for the actual method I used HERE. You can find descriptions and instructions on many methods you'll run into on this API.
Now, back to my answer, that's the easy way to do it. Problem is, this code isn't necessarily safe. It'll throw exceptions if something goes wrong, or if someone is trying to hack into your system. For example, if you were to enter a letter instead of pressing enter or entering a number, it would throw an exception. What you've been seeing in the other answers is what we call exception handling, that's how we make sure exceptions don't happen. If you want an answer that'll catch most of these exceptions, you need to make sure your code catches them, or avoids them all together (I'm simplifying things immensely). The above answer is working code, but isn't safe code, you wouldn't ever use something like this all by itself in real life.
Here is something that might be considered safe code. And no exceptions to keep it simple! ;)
import java.util.Scanner;
public class SOQ15
{
public Scanner scanner;
public SOQ15()
{
scanner = new Scanner(System.in);
int input = 10;
boolean isAnInt = true;
String check;
check = scanner.nextLine/*Int*/();
if(check.equals(""))
{
//do nothing since input already equals 10
}
for(int i = 0; i < check.length(); i++)
{
if(check.charAt(i) >= '0' && check.charAt(i) <= '9' && check.length() < 9)
{
//This is if a number was entered and the user didn't just press enter
}
else
{
isAnInt = false;
}
}
if(isAnInt)
{
input = Integer.parseInt(check);
System.out.println("Here's the number - " + input);
}
}
public static void main(String[] args)
{
SOQ15 soq = new SOQ15();
}
}
I don't have time to go into all the details right now, but ask and I'll gladly respond when I get the time! :)
Well if you are using scanner, given the details provided, you can try:
Scanner in = new Scanner(System.in);
if in.hasNextInt(){ //Without this, the next line would throw an input mismatch exception if given a non-integer
int i = in.nextInt(); //Takes in the next integer
}
You said you wanted a default of 10 otherwise so:
else {
int i = 10;
}

How to verify textField input?

I know this shouldn't be too difficult but my searching hasn't led to anything useful yet. All I want to do is make sure the user inputs a positive integer into a textField. I've tried:
public class myInputVerifier extends InputVerifier {
#Override
public boolean verify(JComponent jc) {
String text = ((jTextFieldMTU) jc).getText();
//Validate input here, like check int by try to parse it using Integer.parseInt(text), and return true or false
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
So in my main code I want to use this to display "OK" if successful and "Enter a positive number" if not successful.
Can someone point me in the right direction please? Thanks!
You could use a try-catch block to check if the input is an integer:
try {
int i = Integer.parseInt(input);
// input is a valid integer
}
catch (NumberFormatException e) {
// input is not a valid integer
}
String has a matches method you can use with regular expressions to see if the contents match a particular pattern. The regular expression for positive integers is ^[1-9]\d*$ so you can use it like this...
boolean matches = text.matches("^[1-9]\d*$");
if(matches){
//Do something if it is valid
}else{
//Do something if it is not
}
I suggest you use try catch.
Catch the NumberFormatException.
In this way you check if the text can be parsed to an integer. If not you can display an error message to the user.
After that you can us an if else statement to check if the number is positive if not positive you can give the user an error message. I suggest you research try catch if you don't know it.

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