Why Java’s Ternary Operator Can Throw NPE: Autoboxing Pitfalls Explained
The article explains how Java’s ternary operator can cause NullPointerException when type inference leads to automatic unboxing of a null wrapper, demonstrates this with concrete code examples, decompiled bytecode, and offers strategies such as using consistent types or replacing the ternary with if‑else.
Background
During integration testing a feature, a NullPointerException appeared only in the test environment. The failing line was:
user.setIsAdmin(Objects.isNull(org) ? 0 : org.getIsAdmin());
user.setIsMask(Objects.isNull(org) ? 0 : org.getIsMask());The first line succeeded, the second threw NPE because org was null and org.getIsMask() returned null, triggering automatic unboxing.
Autoboxing and Unboxing
Since JDK 1.5 Java automatically converts between primitive types and their wrapper classes. Autoboxing wraps a primitive into its wrapper, e.g.:
int a = 5;
Integer b = a; // autoboxingAutoboxing uses Integer.valueOf(), which benefits from a cache for values –128 to 127, allowing == comparison within that range. Unboxing converts a wrapper back to a primitive, e.g.:
Integer a = 5; // autoboxing
int b = a; // unboxingUnboxing is performed by calling the wrapper’s xxxValue() method (e.g., intValue()), and if the wrapper reference is null a NullPointerException is thrown.
Ternary Operator
The ternary syntax is result = condition ? value1 : value2;. The compiler infers a common result type from value1 and value2. When the inferred type is a wrapper and one branch is null while the other is a primitive, the compiler inserts an unboxing conversion for the null branch, causing NPE at runtime.
3.1 Mixed wrapper and primitive (result is wrapper)
boolean flag = true;
Integer result;
Integer value1 = null;
int value2 = 8;
result = flag ? value1 : value2;Running this code throws java.lang.NullPointerException. Decompiling shows the compiler generated value1.intValue(), i.e., an unboxing of null.
3.2 Both branches primitive (result is wrapper)
boolean flag = true;
Integer result;
int value1 = 6;
int value2 = 8;
result = flag ? value1 : value2;Result is 6 and no exception occurs. Decompiled code shows the primitive value is boxed after the conditional.
3.3 Both branches wrapper (result is wrapper)
boolean flag = true;
Integer result;
Integer value1 = null;
Integer value2 = 8;
result = flag ? value1 : value2;Result is null; no exception because no unboxing is required.
3.4 All primitives (result is primitive)
boolean flag = true;
int result;
int value1 = 6;
int value2 = 8;
result = flag ? value1 : value2;Result is 6; primitives cannot be null, so no NPE.
3.5 Result primitive, branches wrapper
boolean flag = true;
int result;
Integer value1 = null;
Integer value2 = 8;
result = flag ? value1 : value2;Running throws NPE because the compiler unboxes value1 to int.
3.6 Result primitive, mixed branches
boolean flag = true;
int result;
Integer value1 = null;
int value2 = 8;
result = flag ? value1 : value2;Again a NullPointerException occurs due to unboxing of the null wrapper.
Conclusion: Whenever the three involved types differ and an automatic unboxing of a null wrapper occurs, a NullPointerException is produced.
Solution
To avoid the NPE:
Ensure both branches of the ternary operator have the same type (both primitives or both wrappers).
Prefer using if‑else when a wrapper may be null, e.g.:
Integer a = null;
Integer result = (a != null) ? a : Integer.valueOf(0);
// or
Integer result;
if (a != null) {
result = a;
} else {
result = Integer.valueOf(0);
}These approaches prevent the compiler from inserting an unwanted unboxing conversion.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Shepherd Advanced Notes
Dedicated to sharing advanced Java technical insights, daily work snippets, and the power of persistent effort.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
