liveBook · Manning

Widening conversion

As explained in 100 Java Mistakes and How to Avoid Them

A widening conversion converts a value to a type with a broader representable range or compatible numeric domain without requiring an explicit cast or conversion operation.

A widening conversion changes a primitive value to a broader type, usually without an explicit cast. Java performs it implicitly in arithmetic, assignments, returns, argument passing, and unary plus. Although the value is usually preserved, widening can change character literals into integer codes, propagate negative byte bits, or round large integers. section 2.5 section 4.6

Watch for these narrowly scoped failure modes:

  • Unary plus widens a char to int. A duplicated plus in string concatenation can turn a quotation mark into code 34, producing output such as `User not found: 34User"` instead of the intended message. section 2.5
  • Widening a negative byte sign-extends it. In bitwise composition, `-1` becomes `0xFFFFFFFF`, so an unmasked low byte can corrupt the entire result. section 4.13
  • Widening can lose precision when converting `int` or `long` to `float`, or `long` to `double`. At sufficiently large values, distinct integers round to the same floating-point number. section 4.6

Preventing unintended widening

Prefer a one-character string over a character literal when concatenating punctuation, and use formatting calls when suitable. Mask bytes before bitwise composition: `((hi & 0xFF) << 8) | (lo & 0xFF)`. Avoid `float` unless justified, make intended floating-point widening explicit with a cast, and use `BigDecimal` when controlled precision matters. section 2.5 section 4.13 section 4.6

String error(String userName) { 
  return "User not found: " + 
        + '"' + userName + '"'; 
}

Inspect the duplicated-plus concatenation that applies unary plus to a quotation-mark character. section 2.5

int readTwoBytes() {
  byte lo = readLowByte();
  byte hi = readHighByte();
  return (hi << 8) | lo;
}

Compare unmasked byte composition with the sign-extension hazard described above. section 4.13

long longVal = 1L << 53;
double doubleVal = longVal;
double doubleValPlusOne = longVal + 1;
System.out.println(doubleVal == doubleValPlusOne);     #1

Observe two distinct long values becoming equal after widening to double. section 4.6

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Explains sign extension, character-code conversion, and floating-point rounding with focused snippets, but does not develop conversion rules comprehensively.
Examples
Uses malformed string concatenation, unmasked two-byte assembly, and long values whose widened double representations compare equal.
What it assumes
Assumes Java primitive-type and operator knowledge while clarifying negative bytes, implicit conversion sites, and precision thresholds.
What you can do after
Diagnose unintended conversion by inspecting types and ranges, then apply masks, explicit casts, safer literals, formatting, or precision-aware numeric types.
How it connects
Connects widening conversion to unary operators, string concatenation, primitive types, bitwise operations, floating-point precision, static analysis, and BigDecimal.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Java Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.