Here’s a silly gotcha in the Java language. I’ve got a method that parses a String
to an int
and returns a default value if the String
cannot be parsed:
int parseOrDefault(String val, int def) {
try {
return Integer.parseInt(val);
} catch (NumberFormatException e) {
return def;
}
}
I’ve got the same for other numeric types including long
, double
and float
:
long parseOrDefault(String val, long def) {
try {
return Long.parseLong(val);
} catch (NumberFormatException e) {
return def;
}
}
float parseOrDefault(String val, float def) {
try {
return Float.parseFloat(val);
} catch (NumberFormatException e) {
return def;
}
}
double parseOrDefault(String val, double def) {
try {
return Double.parseDouble(val);
} catch (NumberFormatException e) {
return def;
}
}
I call each method with:
- A
String
that can be parsed; - A
String
that cannot be parsed and; - A
null
String
PARSABLE = "42";
UNPARSABLE = "forty-two";
NULL = null;
System.out.println("Parsing: " + PARSABLE);
System.out.println(parser.parseOrDefault(PARSABLE, -1));
System.out.println(parser.parseOrDefault(PARSABLE, -1L));
System.out.println(parser.parseOrDefault(PARSABLE, -1.0F));
System.out.println(parser.parseOrDefault(PARSABLE, -1.0D));
System.out.println("Parsing: " + UNPARSABLE);
System.out.println(parser.parseOrDefault(UNPARSABLE, -1));
System.out.println(parser.parseOrDefault(UNPARSABLE, -1L));
System.out.println(parser.parseOrDefault(UNPARSABLE, -1.0F));
System.out.println(parser.parseOrDefault(UNPARSABLE, -1.0D));
System.out.println("Parsing: " + NULL);
System.out.println(parser.parseOrDefault(NULL, -1));
System.out.println(parser.parseOrDefault(NULL, -1L));
System.out.println(parser.parseOrDefault(NULL, -1.0F));
System.out.println(parser.parseOrDefault(NULL, -1.0D));
The result is:
Parsing: 42
42
42
42.0
42.0
Parsing: forty-two
-1
-1
-1.0
-1.0
Parsing: null
-1
-1
Exception in thread "main" java.lang.NullPointerException
at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1838)
at java.base/jdk.internal.math.FloatingDecimal.parseFloat(FloatingDecimal.java:122)
at java.base/java.lang.Float.parseFloat(Float.java:455)
at Parser.parseOrDefault(Parser.java:47)
at Parser.main(Parser.java:25)
Float.parseFloat() and Double.parseDouble() are not consistent with Integer.parseInt() and Long.parseLong(). The integer types Integer
and Long
throw NumberFormatException when provided with a null String
. The floating point types Float
and Double
throw NullPointerException. Both NumberFormatException
and NullPointerException
are unchecked RuntimeExceptions
so you might miss this mistake until it fails at runtime.
If you want to safely parse Float
and Double
, remember to check for null
or catch NullPointerException
.
float parseOrDefault(String val, float def) {
try {
return Float.parseFloat(val);
} catch (NumberFormatException | NullPointerException e) {
return def;
}
}
double parseOrDefault(String val, double def) {
try {
return Double.parseDouble(val);
} catch (NumberFormatException | NullPointerException e) {
return def;
}
}
Be First to Comment