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, so 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.
