liveBook · Manning

Implicit conversion

As explained in 100 Java Mistakes and How to Avoid Them

Implicit conversion is an automatic type conversion performed by Java according to its conversion rules without an explicit cast or conversion call.

Implicit conversion is a Java conversion performed by language rules rather than an explicit cast or conversion call. It can make compact expressions behave differently from their apparent intent: numbers become strings during concatenation, numeric values widen and narrow in compound assignments, conditional-expression branches may be converted unexpectedly, and generic reads can receive compiler-inserted casts. section 2.3 section 2.6 section 4.9 section 5.3.2

Do not confuse implicit conversion with arbitrary conversion. Java does not implicitly convert boolean or Boolean values to other types, so several precedence mistakes in conditions fail at compilation. The more dangerous cases are type-compatible expressions that compile successfully while changing a value, selecting string concatenation instead of arithmetic, or postponing a failure until a generic value is read. section 2.2 section 2.3 section 5.3.2

Concatenation changes the meaning of +

In `"Entry#" + index + 1`, evaluation proceeds left to right. Once the first `+` produces a string, the number is converted to text and the final `+ 1` concatenates rather than increments. With `index = 4`, the result is `Entry#41`, not `Entry#5`. Parenthesize the arithmetic as `"Entry#" + (index + 1)`, compute it in an intermediate variable, or use a formatting API when that better expresses the intent. section 2.3 section 2.3

String entryName = "Entry#" + index + 1;

This short expression isolates the conversion boundary: after the string literal participates in `+`, later numeric operands are concatenated as strings. section 2.3

Compound assignments hide a particularly important conversion. `x *= y` behaves as `x = (type_of_x)(x * y)`, not simply as `x = x * y`. The operation can widen a small integral type for computation and then implicitly narrow the result back to the target type. Thus `char c = 'a'; c *= 1.2;` yields a narrowed character result even though no cast appears in the source. section 4.9 section 4.9

A byte update that does nothing

Trying to turn a negative byte into its unsigned-looking value with `b += 256` fails when `b` remains a `byte`. Java widens `b` to `int`, adds 256, then narrows the value back into the byte range, restoring the original value. Use an `int` result, such as `Byte.toUnsignedInt(getByte())`, when the required range is 0 through 255. The same widen-then-narrow pattern can make `b >>>= 1` leave a byte value unchanged. section 4.9 section 4.9 section 4.9

byte b = getByte();
if (b < 0) {
  b += 256;     #1
}

The assignment looks like an in-place unsigned conversion, but its byte target forces an implicit narrowing conversion after the addition. section 4.9

A ternary expression is often read as a compact `if`/`else`, but numeric branches can have different semantics because conditional expressions apply their own type-conversion rules. When branch types differ and the result matters, prefer an `if` statement if the conversion is unclear rather than assuming the two forms are interchangeable. section 2.6 section 2.15

Generics add a different form of implicit conversion: an implicit cast inserted by the compiler. At run time, generic type arguments are erased, so `list.get(0)` is effectively an `Object` result followed by a cast when assigned to `String`. An unchecked cast or raw-type use can corrupt a list earlier and cause `ClassCastException` only later at that hidden cast. section 5.3.2 section 5.3

void printFirstItem(List list) {
  String s = (String) list.get(0);
  System.out.println(s);
}

This desugared form makes the otherwise invisible cast explicit: the generic read is treated as an `Object` and then cast to `String`. section 5.3.2

Reduce conversion-related surprises with explicit intent:

  • Parenthesize arithmetic embedded in string concatenation, or separate the arithmetic into a named variable. section 2.3
  • Inspect the target type of every compound assignment and assume narrowing is possible when the target is `byte`, `short`, or another smaller type. section 4.9
  • Prefer `int` or `long` over `byte` and `short` where practical; use `Byte.toUnsignedInt` for an unsigned byte value. section 4.9
  • Avoid unchecked casts and raw generic types; use wildcard types or checked and unmodifiable list alternatives when appropriate. section 5.3.2
  • Treat static-analysis reports as useful but incomplete: the cited inspection detects some no-op updates, not every complex conversion case. section 4.9

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Explains conversion consequences through concatenation, conditional expressions, compound assignments, and erased generics, with avoidance guidance and inspection limits.
Examples
Uses `"Entry#" + index + 1`, `char c *= 1.2`, byte updates and shifts, and a `List<String>` read.
What it assumes
Assumes familiarity with Java expressions, primitive types, casts, and generic collections while clarifying their hidden conversion behavior.
What you can do after
Diagnose/debug with it by spotting hidden string, numeric, and generic casts and choosing explicit safer alternatives.
How it connects
Connects string concatenation, operator precedence, conditional expressions, numeric overflow, generics, type erasure, and ClassCastException.

Also explained in

Compare how 4 books explain implicit conversion →

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.