Today I was coding in Java and I came across a part of the code where I was using a byte literal. I’ve been using Java for a while, so I knew that you have to suffix long literals with an ‘L’ otherwise Java complains.
long myLong = 3000000000L; // Java is happy
long myOtherLong = 3000000000; // Java is sad (too big for int)
So when I went to create my byte literal I figured I would need to put a suffix on the number, like I do with long literals. But when I tried it, it turns out I didn’t need to.
byte myByte = 12; // Java is happy
byte myByte = 12B; // Java is sad
Long Needs an L Suffix
So I looked into it and found out that Java integer literals are always created as int by default. This makes sense because I knew that when I forgot the ‘L’ when assigning a value to a long, the message was about trying to assign an int to a long variable. So, to tell Java that you are in fact trying to assign a long literal to a long variable, you include the ‘L’. If you don’t provide the ‘L’, Java gets confused.
Java Doesn’t Have a B Suffix for byte
Java automatically converts integer values to byte if they are within the valid range for a byte type (-128 to 127). This is called a narrowing primitive conversion, and Java allows it for compile-time constants that fit in the target range. So Java will automatically convert a value, say 1, to a byte and assign it. You can also explicitly cast it if you prefer.
byte b = (byte) 1; // Java is happy
byte b = 1; // Java is happy
This is good to know but seems counterintuitive. I would think that an automatic type conversion would be allowed when putting a type with a smaller range into one of a larger range because there is no risk of overflow. Why does it work in the opposite way?
The answer is that Java does allow widening conversions (small to large) implicitly — you can assign a byte to an int without casting. But for narrowing conversions (large to small), Java normally requires an explicit cast because data could be lost. The exception is compile-time constants: if Java can verify at compile time that the value fits, it allows the assignment without a cast. That’s why byte b = 12; works but byte b = someIntVariable; would not.