Mixed Wrapper Types In Ternary

ID

java.dissimilar_primitive_wrappers_ternary_operator

Severity

high

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Code Smell

Language

Java

Tags

reliability

Description

Reports a ternary conditional expression (cond ? a : b) whose two branches box different numeric wrapper types, such as Integer and Float. The compiler does not simply return whichever branch the condition selects: it unboxes both branches and applies binary numeric promotion to compute one common type for the whole expression.

Rationale

Integer, Long, Float, Double, Byte, Short and Character all satisfy the ternary’s "numeric type" rule, so mixing any two of them forces the compiler to unbox both operands and promote them to a common numeric type, even the one that was not selected by the condition. An int promoted to float can silently lose precision once the value exceeds 2^24, and the unboxing itself throws a NullPointerException if either boxed value is null — neither consequence is visible at the call site.

Integer count = 123456789;
Float estimate = 1.0f;

// Bad -- both operands are unboxed and promoted to float, regardless of which one is picked
Number result = useEstimate ? estimate : count;

Remediation

Cast one branch to a common reference supertype (typically Number) to keep both values boxed and skip the coercion, or, if the coercion was genuinely intended, cast explicitly to the target primitive type so the conversion is visible in the code.

Integer count = 123456789;
Float estimate = 1.0f;

// Good -- explicit cast keeps the value boxed, no coercion happens
Number result = useEstimate ? estimate : (Number) count;

// Good -- explicit cast makes the intended coercion visible
float narrowed = useEstimate ? estimate : (float) count;

© 2026 Xygeni. All rights reserved