I found a strange behaviour in the current version of Java 8. In my opinion the following code should be fine, but the JVM throws a NullPointerException
:
Supplier<Object> s = () -> false ? false : false ? false : null;
s.get(); // expected: null, actual: NullPointerException
It doesn't matter, what kind of lambda expression it is (same with java.util.function.Function
) or what generic types are used. There can also be more meaningful expressions in place of false ? :
. The example above is very short. Here's a more colorful example:
Function<String, Boolean> f = s -> s.equals("0") ? false : s.equals("1") ? true : null;
f.apply("0"); // false
f.apply("1"); // true
f.apply("2"); // expected: null, actual: NullPointerException
However these code pieces run fine:
Supplier<Object> s = () -> null;
s.get(); // null
and
Supplier<Object> s = () -> false ? false : null;
s.get(); // null
Or with function:
Function<String, Boolean> f = s -> {
if (s.equals("0")) return false;
else if (s.equals("1")) return true;
else return null;
};
f.apply("0"); // false
f.apply("1"); // true
f.apply("2"); // null
I tested with two Java versions:
~# java -version
openjdk version "1.8.0_66-internal" OpenJDK Runtime Environment (build 1.8.0_66-internal-b01) OpenJDK 64-Bit Server VM (build 25.66-b01, mixed mode)
C:\>java -version
java version "1.8.0_51" Java(TM) SE Runtime Environment (build 1.8.0_51-b16) Java HotSpot(TM) 64-Bit Server VM (build 25.51-b03, mixed mode)
This has nothing to do with lambda expressions; it is simply that the return type of the ternary operator in that case is boolean
, so auto-unboxing will be used.
NPE is thrown here as well:
public class Main {
private static Object method() {
return false ? false : false ? false : null;
}
public static void main(String[] args) {
System.out.println(method());
}
}
So, what exactly is happening here?
Firstly, 'embedded' expression (false ? false : null
) is evaluated according to JLS §15.25:
The conditional operator is syntactically right-associative (it groups right-to-left). Thus, a?b:c?d:e?f:g means the same as a?b:(c?d:(e?f:g)).
The type of the embedded expression is Boolean
(boxed boolean
), so that both false
and null
can fit into it.
Then the whole expression is:
false ? false : (Boolean expression)
Then, again according to JLS §15.25:
If one of the second and third operands is of primitive type T, and the type of the other is the result of applying boxing conversion (§5.1.7) to T, then the type of the conditional expression is T.
So, the first argument is of primitive type boolean
(T
in the spec), the type of the other is the boxed T
(Boolean
), so the type of the entire expression is boolean
.
Then, in runtime, the embedded expression evaluates to null
which is auto-unboxed to boolean
, causing the NPE.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With