FULL PRODUCT VERSION :
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b18)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b18, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.3.9600]
EXTRA RELEVANT SYSTEM CONFIGURATION :
I am using:
Eclipse Java EE IDE for Web Developers.
Version: Luna Service Release 2 (4.4.2)
Build id: 20150219-0600
A DESCRIPTION OF THE PROBLEM :
I have a method called toInteger to parse a string to a Integer. It receives two arguments, the string to parse and a replacement if the string cannot be parsed.
The arguments are:
value : String, replace : Integer
the body method:
return value == null ? replace : isInteger(value) ? Integer.parseInt(value) : replace;
*the method isInteger receives string : String, and returns boolean:
return string != null && string.matches("-?\\d+");
I call toInteger passing a string and a null as a replacement.
In case that the string value is null, it has to return the null replacement, and in case the string value is not null nor a numeric string, it has to return the null replacement too. In any of that two cases it doesn't performs the Integer.parseInt method. But the call to toInteger with a null replacement throws a NullPointerException (not a NumberFormatException).
That is curious is that if I encapsulate the Integer.parseint to an another method, in my case called parseInt, the toInteger returns the null replacement without throwing the NullPointerException.
I have tried with a shorter expression without nesting conditional operators, and well, a better expression:
return value == null && isInteger(value) ? parseInt(value) : replace;
That returns the null replacement without the NullPointerException.
I think the bug is nesting conditional operators.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Executing the attached source code is sufficient, is a short source.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
When I pass a unparseable string as a first argument, and a null replacement as a second argument, I expected the toInteger method to return null.
ACTUAL -
The actual result for the toInteger method is a NullPointerException,
but returns the expected null when calling the methods toInteger2, that encapsulates de Integer.parseInt, toInteger3 and toInteger4, that both avoids nested conditional operators.,
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package main;
public class Main {
public static void main(String[] args) {
ints();
}
public static void ints() {
try {
Integer i = toInteger(null, null);
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
}
try {
Integer i = toInteger2(null, null);
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
}
try {
Integer i = toInteger3(null, null);
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
}
try {
Integer i = toInteger4(null, null);
System.out.println(i);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Integer toInteger(final String value, final Integer replace) {
//NullPointerException if replace is null
return value == null ? replace : isInteger(value) ? Integer.parseInt(value) : replace;
}
public static Integer toInteger2(final String value, final Integer replace) {
//Encapsulates Integer.parseInt with parseInt
return value == null ? replace : isInteger(value) ? parseInt(value) : replace;
}
public static Integer toInteger3(final String value, final Integer replace) {
return value == null && isInteger(value) ? parseInt(value) : replace;
}
public static Integer toInteger4(final String value, final Integer replace) {
if (value != null && isInteger(value)) {
return Integer.parseInt(value);
} else {
return replace;
}
}
public static boolean isInteger(final String string) {
return string != null && string.matches("-?\\d+");
}
public static Integer parseInt(final String value) {
return Integer.parseInt(value);
}
}
---------- END SOURCE ----------