What is the best practice in Java to check for invalid parsing results while using a "default value" instead of exceptions?
The (old-grown) project I'm working on has a fail-safe util-method to parse String
to double
like:
//null checks, LOG output etc removed for readability
double parseDouble(String input, double defaultValue){
try{
return Double.parseDouble(input)
} catch (Exception e){
return defaultValue;
}
}
Now the previous developer(s) always used a default value like returnedValue = parseDouble(someString, -99);
and a check like if(returnedValue == -99)
to identify an invalid parsing result. The (finally) added SonarQube server complains about this check using ==
on double
and I want to replace these checks with a "correct" check.
What is the best practice to handle such cases?
I personally would use
parseDouble(someString, Double.NaN);
and accordingly the check if(Double.isNan(returnedValue)
. Is this a viable solution?
EDIT: I forgot to mention, that the utility class is not editable (from my point) and therefore I'm looking on how to easily "fix" the existing code. Also adding third-party libraries would be nice but is (at this point in time) not possible either.
In old times I also would have gone with the NAN or POSITIVE_INFINITY or MAX_VALUE or any other that isn't used. Now I would use Optional-class. Using integers is not reliable because of conversion and using null is Hoares one-billion-dollar mistake: Does null mean error, not initialized, not given? Was the input string null or was it parsed and it was not a valid double representation?
Basically you do not want a method that gives you back a default value when there was a parsing error or null input or the user entered the default value. You want a method that gives you back the information wether there was an error or not, and if not then the parsed value. To make your code more readable and easier understandable I would write exactly such a method and use it everywhere where appropriate (instead of copy-pasting workarounds everywhere). If you cannot put it into the existing utility class, make your own additional utility class. If you are using Java 8, you can make use of Optional-class. If not, then program your own Optional (or grab it from some library). Here is the utility method:
Optional<Double> parseDouble(String input) {
try {
return Optional.of(Double.parseDouble(input));
} catch (Exception e) {
return Optional.empty();
}
}
Here is how to use it:
String input = ...;
Optional<Double> parsedInput = parseDouble(input);
if (! parsedInput.isPresent()) {
// print out warning and retry input or whatever
}
double convertedInput = parsedInput.value();
Remark:
SonarQube would also critizise catching a common "Exception". Instead you should catch NumberFormatException and NullPointerException. When the caller needs to know the exact cause you can the add a method getEmptyReason() to your Optional (or derived class) and store the exception reason there. But I guess in your case you want to use a default value if the input string was not given (empty or null) and want to make an error handling if the value was given but unparseable. In this case you can use:
Optional<Double> parseDouble(String input, double defaultValue) {
if (input == null || input.trim().length == 0) {
return Optional.of(defaultValue);
}
try {
return Optional.of(Double.parseDouble(input));
} catch (NumberFormatException e) {
return Optional.empty();
}
}