Reputation: 81
Why do my JOptionPane.showInputDialog windows disappear before I can enter an input? I think it's what's causing my code to break. I've googled everything I can think of and nothing seems to apply to what I'm doing here. The error I get is:
Exception in thread "main" java.lang.NumberFormatException: For input string: ""
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:678)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at ChiliToGo.collectOrder(ChiliToGo.java:25)
at ChiliToGo.main(ChiliToGo.java:13)
I'm just in a beginner java course so It's probably really dumb what I'm doing.
I've tried formatting the string and moving the main method into a separate class to access the methods in a non-static way because they are the best solutions I got from the posts I found. I'm just really confused because the parseint shouldn't get the string until I press ok right? It's only there for a moment and I don't have a chance to enter the input
Any help would be appreciated, code is below. Sorry if I made any mistakes this is my first post
import javax.swing.JOptionPane;
public class ChiliToGo {
static int adultMeal = 7;
static int kidsMeal = 4;
static String adultMealOrder;
static String kidsMealOrder;
static int adultMealOrdered;
static int kidsMealOrdered;
static int totalPrice;
public static void main(String[] args) {
collectOrder();
finalizeOrder();
}
public static void collectOrder() {
adultMealOrder = JOptionPane.showInputDialog("Please enter the number of adult meals:");
kidsMealOrder = JOptionPane.showInputDialog("Please enter the number of kids meals:");
adultMealOrdered = Integer.parseInt(adultMealOrder);
kidsMealOrdered = Integer.parseInt(kidsMealOrder);
}
public static void finalizeOrder() {
for(int i = 0; i < adultMealOrdered; i++) {
totalPrice = totalPrice + adultMeal;
}
for(int n = 0; n < kidsMealOrdered; n++) {
totalPrice = totalPrice + kidsMeal;
}
JOptionPane.showInternalMessageDialog( null, "Your order total is: " + totalPrice, null, JOptionPane.INFORMATION_MESSAGE);
}
}
Upvotes: 0
Views: 364
Reputation: 347332
So, the error is telling you that the input value of ""
can't be converted to int
. You're not doing any validation on the String
returned from showInputDialog
and are simply, blindly, trying to convert it to an int
, which is failing, because no input has been made (and even worse, the return value could be null
).
The following is a "conceptual" idea which encompasses the input/validation into a self contained and re-usable unit of work. This "concept" could be used for console input as well.
The intention isn't to "answer" the question directly, but offer (not only an answer), but a conceptual and re-usable workflow and encourage a different way of "thinking" when approaching these kind of issues.
There are any number of ways you "might" consider fixing this, but the basic idea is to:
null
int
value.To this end, I might encapsulate the logic into a self contained unit of work, for example...
public static Integer getIntFromUser(String prompt) {
Integer result = null;
boolean done = false;
do {
String value = JOptionPane.showInputDialog(prompt);
// User pressed cancel
if (value == null) {
done = true;
} else {
Scanner scanner = new Scanner(value);
if (scanner.hasNextInt()) {
result = scanner.nextInt();
done = true;
} else {
JOptionPane.showMessageDialog(null, "Please enter a numeric value");
}
}
} while (!done);
return result;
}
This will loop until the user either inputs a valid int
value or presses Cancel (hence the reason it returns Integer
instead of int
, this way you can inspect the return value for null
)
The collectOrder
method would also change to look something more like...
public static boolean collectOrder() {
boolean validUserInput = false;
Integer inputValue = getIntFromUser("Please enter the number of adult meals:");
if (inputValue != null) {
// Only prompt for the kids meal if the adult value is valid,
// otherwise it's likely that they clicked cancel
adultMealOrdered = inputValue;
inputValue = getIntFromUser("Please enter the number of kids meals:");
if (inputValue != null) {
kidsMealOrdered = inputValue;
validUserInput = true;
}
}
return validUserInput;
}
The intention here is to check the return result from getIntFromUser
, if it's null
, the user pressed <kbd>Cancel</kbd>
and we should stop any further processing, otherwise we go onto the next step.
collectOrder
also returns boolean
to indicate whether it has all the required data or not, so we don't try and finalise the order with invalid or partial data.
public static class ChiliToGo {
static int adultMeal = 7;
static int kidsMeal = 4;
static int adultMealOrdered;
static int kidsMealOrdered;
static int totalPrice;
public static void main(String[] args) {
if (collectOrder()) {
finalizeOrder();
}
}
public static boolean collectOrder() {
boolean validUserInput = false;
Integer inputValue = getIntFromUser("Please enter the number of adult meals:");
if (inputValue != null) {
// Only prompt for the kids meal if the adult value is valid,
// otherwise it's likely that they clicked cancel
adultMealOrdered = inputValue;
inputValue = getIntFromUser("Please enter the number of kids meals:");
if (inputValue != null) {
kidsMealOrdered = inputValue;
validUserInput = true;
}
}
return validUserInput;
}
public static Integer getIntFromUser(String prompt) {
Integer result = null;
boolean done = false;
do {
String value = JOptionPane.showInputDialog(prompt);
// User pressed cancel
if (value == null) {
done = true;
} else {
Scanner scanner = new Scanner(value);
if (scanner.hasNextInt()) {
result = scanner.nextInt();
done = true;
} else {
JOptionPane.showMessageDialog(null, "Please enter a numeric value");
}
}
} while (!done);
return result;
}
public static void finalizeOrder() {
for (int i = 0; i < adultMealOrdered; i++) {
totalPrice = totalPrice + adultMeal;
}
for (int n = 0; n < kidsMealOrdered; n++) {
totalPrice = totalPrice + kidsMeal;
}
JOptionPane.showInternalMessageDialog(null, "Your order total is: " + totalPrice, null, JOptionPane.INFORMATION_MESSAGE);
}
}
But why not use a try-catch block?
Well, this might be a little old school, and you don't always have the choice, but try-catch
blocks, generally, shouldn't be used as control flow mechanisms (every rule has an exception 😉)
Upvotes: 1
Reputation: 6188
Your problem is that you have no error handling. If any of the dialogs that set the adultMealOrder
or kidsMealOrder
is left blank, when you try to parse the integer value, it throws an exception. You must handle the exception and convert the blank String value to zero. Basically, the function cannot convert an empty string into a number. You must do it yourself.
try {
adultMealOrdered = Integer.parseInt(adultMealOrder);
} catch (NumberFormatException nfe) {
adultMealOrdered = 0;
}
Another way to handle this, is to check the output of the dialog function and continue to prompt until the output is not null or not empty.
while (adultMealOrder == null || adultMealOrder.isBlank()) {
adultMealOrder = JOptionPane.showInputDialog("Please enter the number of adult meals:");
}
I personally rather add the error handling on the parseInt
function rather than this, but it is an option nevertheless.
You have other issues:
EXIT_ON_CLOSE
), this problem should be fixed.for(int i = 0; i < adultMealOrdered; i++) {
totalPrice = totalPrice + adultMeal;
}
for(int n = 0; n < kidsMealOrdered; n++) {
totalPrice = totalPrice + kidsMeal;
}
Should be simplified to this:
totalPrice = (adultMealOrdered * adultMeal) + (kidsMealOrdered * kidsMeal);
Upvotes: 0