Reputation: 10229
In a certain try block, I have two String
variables which could cause NumberFormatException
when I user Integer.parseInt(string1)
andInteger.parseInt(string2)
. The question is, if I catch
an exception, how to know which string is the troublemaker? I need to get the troublemaker's variable name.
Here is some example code:
public class test {
public static void main(String[] args) {
try {
String string1 = "fdsa";
String string2 = "fbbbb";
Integer.parseInt(string1);
Integer.parseInt(string2);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}
And the method e.printStackTrace()
doesn't tell me the variable name; it just tells me the content of the troublemaker.
java.lang.NumberFormatException: For input string: "fdsa" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Integer.parseInt(Integer.java:580) at java.lang.Integer.parseInt(Integer.java:615) at test.main(test.java:9) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Process finished with exit code 0
The reason that I need to know the variable's name is that I need to prompt the user what's going on. For instance, tell the user that string1 is wrong by using
System.out.println(troubleMakerName + "is wrong!")
In my Requirements, the user should input
fd=(fileName,maxLength,minLength)
then I will analyse the input string and create some responses. So I'd like to check whether the maxLength
and minLength
will throw NumberFormatException
. In this case, if minLength
has something wrong, then I need to prompt the user that the minLength is wrong.
Upvotes: 41
Views: 4614
Reputation: 7820
You are having an XY-Problem.
You don't want to read the actual variable name. You want to be able to validate input and give reasonable error messages to your user.
String fileName, maxLengthInput, minLengthInput;
int maxLength, minLength;
List<String> errors = new ArrayList<>();
try {
maxLength = Integer.parseInt(maxlengthInput);
} catch (NumberFormatException nfe) {
errors.add("Invalid input for maximum length, input is not a number");
}
try {
minLength = Integer.parseInt(minlengthInput);
} catch (NumberFormatException nfe) {
errors.add("Invalid input for minimum length, input is not a number");
}
// show all error strings to the user
Not throwing the exceptions directly but collecting them allows you to notify the user about all invalid inputs at once (maybe highlight the related fields with red color) instead of having them fix one input, trying to submit again, and then to see that another input is also wrong.
Instead of Strings you could user your own data struture containing information of the related field etc., but that quickly gets out of scope. The main gist is: use two try-catch blocks, and you are able to differentiate which field is errorneous.
If more inputs are involved, you can refactor this into a loop.
Upvotes: 70
Reputation: 5960
It's quite simplistic, but here's my solution..
public class test
{
public static int tryParseInt(String str) throws Exception
{
try
{
return Integer.parseInt(str);
}
catch(Exception e)
{
System.err.println("tryParseInt: couldn't parse '"+str+"'");
throw e;
}
}
public static void main(String[] args)
{
try
{
String string1 = "fdsa";
String string2 = "fbbbb";
tryParseInt(string1);
tryParseInt(string2);
}
catch (NumberFormatException e)
{
e.printStackTrace();
}
}
}
Upvotes: 0
Reputation: 29
I'm surprised nobody proposed something like this:
public class test {
public static void main(String[] args) {
String errorContext;
try {
String string1 = "fdsa";
String string2 = "fbbbb";
errorContext = "string1";
Integer.parseInt(string1);
errorContext = "string2";
Integer.parseInt(string2);
} catch (NumberFormatException e) {
System.out.println(errorContext + " is wrong!")
e.printStackTrace();
}
}
}
It is a very simple solution - simplistic, some would say - but it is also fairly clear and robust.
The point of this question - as I understand it - was not to provide a better way of converting strings to integers (even if it indeed may exist), but rather to find a way to say not only what went wrong in a long try
block, but also where it went wrong. If one's goal is to display a meaningful error message to the user (ideally suggesting what to do rather than just complaining that something is wrong), then simply printing a stack trace is not sufficient, of course, and try-catching every line of code is not an attractive option either.
Upvotes: 2
Reputation: 20362
Just use another try catch for the other statement
public class test
{
public static void main(String[] args)
{
String string1 = "fdsa";
String string2 = "fbbbb";
try
{
Integer.parseInt(string1);
}
catch (NumberFormatException e)
{
System.out.println("string1 is the culprit");
e.printStackTrace();
}
try
{
Integer.parseInt(string2);
}
catch (NumberFormatException e)
{
System.out.println("string2 is the culprit");
e.printStackTrace();
}
}
}
Upvotes: 3
Reputation: 49656
I would like to write own parseInt
method:
public static int parseInt(String s,
Supplier<? extends RuntimeException> supplier) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
throw (RuntimeException)supplier.get().initCause(e);
}
}
As I know, we can't read a variable name by reflection, so I just pass a String
literal instead:
parseInt(string1, () -> new NumberFormatException("string1"));
I will leave the origin answer and provide a version that has discussed in the comments. But for now, I am confused why a Supplier is an overkill.
public static int parseInt(String s, String message) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
throw (NumberFormatException)new NumberFormatException(message).initCause(e);
// throw new IllegalArgumentException(message, e);
}
}
Its call looks like
parseInt(string1, "string1");
Upvotes: 6
Reputation: 848
You could create a method with a try/catch that returns the value you assign or prints to console that there was a problem, this way you could accommodate for as many variables as you need with one try/catch while still tracking the name of all variables that cause a problem.
public class test {
public static void main(String[] args) {
String string1 = returnString("fdsa", "string1");
String string2 = returnString("fbbbb", "string2");
}
private string returnString(String input, String varName) {
String str = "";
try {
str = input;
Integer.parseInt(str);
} catch (NumberFormatException e) {
System.out.println("Error processing " + varName);
}
return str;
}
}
Upvotes: 2
Reputation: 3193
You should avoid catching Runtime exceptions
and use some other mechanism for identifying errors. In your case you could use matcher and your problem could be written as:
public class test {
private static final Pattern pattern = Pattern.compile("\\d+");
public static void main(String[] args) {
String string1 = "fdsa";
String string2 = "fbbbb";
if (pattern.matcher(string1).matches()) {
Integer.parseInt(string1);
} else {
//string1 is not an integer
}
...
}
}
Or you could just write
boolean errorInLineOne = !pattern.matcher(string1).matches();
...
Upvotes: 0
Reputation: 6782
Use 2 seperate try
,catch
blocks to parse two inputs for each variables. Then generate the sanity check message inside each catch
block.
String string1 = "fdsa";
String string2 = "fbbbb";
try {
Integer.parseInt(string1);
} catch (NumberFormatException e) {
e.printStackTrace();
**//Please provide a valid integer for string1**
}
try {
Integer.parseInt(string2 );
} catch (NumberFormatException e) {
e.printStackTrace();
**//Please provide a valid integer for string2**
}
Upvotes: 10
Reputation: 4948
Before you perform the operation you can write a simple isInteger() function that can return you a boolean. A good implementation can be found on this thread. This uses the radix of the value and iterates if it is an int and is quite handy. Determine if a String is an Integer in Java A simple if conditional then can find which value is rogue in the argument
Upvotes: 4