Narrowing Primitive Cast

ID

java.narrowing_primitive_cast

Severity

low

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Java

Tags

CWE:681, reliability

Description

Reports casts between primitive types that reduce precision or range (narrowing conversions).

Rationale

A narrowing cast silently truncates the value when the source exceeds the target type’s range. For example, (int) 3.9 yields 3 (fractional part lost) and (byte) 300 yields 44 (overflow). These silent truncations are a common source of subtle bugs.

// Bad - double to int loses fractional part
double price = 19.99;
int rounded = (int) price; // 19, not 20

// Bad - long to byte overflows
long big = 100000L;
byte small = (byte) big; // -96, silently overflows

Scope

A cast of a compile-time constant written out of literals, whose value is representable in the target type, is not reported. Nothing is truncated at runtime, and for the small integral types the cast is frequently the only way to write the value at all — Java has no byte or short literal:

// Not reported: the eight bits survive the cast intact
writeToSharedMemory(tmpDir, 1, (byte) 0xFF);
byte rank = (byte) 3;
char marker = (char) 2;
byte mask = (byte) (1 << 3);

The exemption stops at the literal: (byte) i and (byte) (value >>> 16) are still reported, because nothing in the source guarantees what those hold at runtime. A literal too wide for the target, such as (byte) 300, is reported as well.

Remediation

Either validate the value before casting or use a method that handles the conversion safely:

// Good - explicit range check
public static int safeLongToInt(long value) {
    if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
        throw new ArithmeticException("Value out of int range: " + value);
    }
    return (int) value;
}

// Good - use Math.round for floating point
int rounded = (int) Math.round(price);

© 2026 Xygeni. All rights reserved