Java DISCUSSION

Why does b += 1 compile for a Java byte when b = b + 1 gives a lossy conversion error?

Started by prabhakaran compound assignmentnumeric promotionJava bytenarrowing conversionunsigned bytes
4 replies 248 views 5 participants
Latest activity · 30 Sep 2026

Why does b += 1 compile for a Java byte when b = b + 1 gives a lossy conversion error?

prabhakaran Java Forum
#1

I am computing a checksum over a packet with byte sum = 0;. Writing sum = sum + data[i]; fails to compile with "incompatible types: possible lossy conversion from int to byte". Writing sum += data[i]; compiles and runs. Both operands are of type byte, so where does the int come from, and why is one form accepted?

I also get strange output when printing bytes: a received value of 0xF0 prints as -16, and (b >> 4) gives -1 instead of 15. How should byte arithmetic be written for protocol code?

Community replies 4

Re: Why does b += 1 compile for a Java byte when b = b + 1 gives a lossy conversion error?

#2

Java, like C, applies numeric promotion: operands of type byte, short and char are widened to int before +, -, *, &, shifts and so on. So sum + data[i] has the type int, and assigning an int to a byte is a narrowing conversion that Java refuses without an explicit cast: sum = (byte) (sum + data[i]);.

Compound assignment is defined differently. The language specification says E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1. The cast is built in. sum += data[i] keeps the low 8 bits of the result, which is exactly what a modulo-256 checksum wants.

Re: Why does b += 1 compile for a Java byte when b = b + 1 gives a lossy conversion error?

#3

That hidden cast is a trap elsewhere, because it discards information without a word. int i = 5; i += 3.7; compiles and leaves i at 8, where i = i + 3.7 is an error. byte b = 127; b += 1; gives -128. short s = 0; s += 70000; compiles and stores 4464, which is 70000 - 65536. And int total = 0; total += someLong; drops the upper 32 bits of the long.

When the right-hand side is wider than the variable, write the long form with an explicit cast so that the truncation is visible to the reader. Recent JDKs can also warn about this with the -Xlint:lossy-conversions compiler option.

Re: Why does b += 1 compile for a Java byte when b = b + 1 gives a lossy conversion error?

#4

On the negative values: Java's byte is signed, with a range of -128 to 127, and there is no unsigned byte type. The bit pattern 0xF0 is -16. When it is promoted to int it is sign-extended to 0xFFFFFFF0, and the arithmetic shift >> 4 gives 0xFFFFFFFF, which is -1.

The standard idiom is to mask straight after promotion: int u = b & 0xFF; gives 240, and (b & 0xFF) >> 4 gives 15. The unsigned shift does not help with a byte, since b >>> 4 operates on the already sign-extended int and yields 0x0FFFFFFF. Since Java 8, Byte.toUnsignedInt(b) does the same as the mask, and String.format("%02X", b) prints the byte as two hex digits.

Re: Why does b += 1 compile for a Java byte when b = b + 1 gives a lossy conversion error?

#5

For protocol code, keep the raw data in a byte[] but do the arithmetic in int and mask at the boundaries. A 16-bit big-endian value is int v = ((buf[0] & 0xFF) << 8) | (buf[1] & 0xFF);. Without the masks, a low byte of 0x80 or above sign-extends and ORs ones into the upper bits: the bytes 0x12, 0x80 would give 0xFFFFFF80 instead of 0x1280.

For 32-bit unsigned quantities use a long and mask with 0xFFFFFFFFL. The L matters, because 0xFFFFFFFF alone is the int -1. Alternatively, ByteBuffer.wrap(buf).order(ByteOrder.LITTLE_ENDIAN) with getShort() and getInt() does the assembly for you with an explicit byte order; its default is big-endian.

TEP COMMUNITY