Reputation: 181
So reading through the documentation, it states that if you declare an int literal with an L on the end, it will read it as a long instead. Here is my question: is there any difference between this and just naming the type as a long to start with? For example:
int x = 100L;
VS.
long x = 100;
The same thing?
Upvotes: 8
Views: 17317
Reputation: 338416
is there any difference …
int x = 100L;
versuslong x = 100;
Yes. There is a major difference.
long
into a 32-bit int
. Instead, call Math.toIntExact
.int
primitive integer literal while being assigned to a 64-bit long
primitive integer variable.int |
long |
|
---|---|---|
Bits | 32-bit | 64-bit |
Range | -231 through 231-1 (≈ ±2 billion) (−2,147,483,648 through 2,147,483,647) |
-263 through 263-1 (≈ ±9 quintillion) (−9,223,372,036,854,775,808 through 9,223,372,036,854,775,807) |
Literal | 42 ( int by default) |
42L or 42l (Uppercase is more readable) |
Assign value to the other type | widening (legal) |
narrowing (illegal) |
Casting to other type | widening (unnecessary, supported implicitly) |
potential data-loss (any data loss goes unnoticed, use Math.toIntExact instead) |
Wrapper class | Integer |
Long |
There is much misinformation in the other Answers.
The L
seen above means “64-bit long
integer primitive” whereas the absence of a L
in an integer literal means “32-bit int
integer primitive”.
The following line fails to compile. You are attempting to place a 64-bit long
primitive literal into a 32-bit int
variable. Square peg, round hole. One of the compiler’s jobs is to stop such nonsense.
int x = 100L ; // BAD — compiler fails — Cannot place a 64-bit `long` `int` primitive in a 32-bit `int` variable.
Error … incompatible types: possible lossy conversion from long to int
Let’s correct that line by dropping the L
, assigning a 32-bit int
literal to a 32-bit int
variable.
int x = 100 ; // 32-bit `int` integer primitive literal being stored in a 32-bit `int` integer variable. No problem, no issues.
Notice that, contrary to some incorrect Answers seen on this page, the code above has no objects, only primitives.
In the line of code below, you are first creating a 32-bit int
primitive with the “100” part. That 32-bit int
primitive is then assigned to a 64-bit long
primitive. Java fills in the extra thirty-two bits with zeros, so effectively you end up with the same number.
long x = 100 ; // 32-bit `int` integer primitive being stored in a 64-bit `long` integer primitive. The extra 32-bits are filled in with zeros automatically by Java.
As noted in a comment by Andreas, this conversion from 32-bit to 64-bit integers is technically called widening. See JLS 5.1.2 Widening Primitive Conversion for a technical discussion.
Some people, including me, consider such code using literals that depend on automatic widening to be poor form. Your intentions as a programmer are ambiguous. So I would write that code using the appended L
, like this long x = 100L ;
. But some folks would consider this position to be needless worry about an inconsequential matter.
Contrary to some other Answers, there is no casting involved in the code seen above.
Here is an example of casting. We start with a 64-bit long
primitive. When then cast to an int
primitive, lopping off the higher 32-bits. The (int)
tells the compiler “yes, I know I am risking data loss in chopping off 32 of my 64 bits, but go ahead and do it, I am taking responsibility for this act”.
int x = (int) 100L ; // Start with a 64-bit `long` primitive literal, lop off 32 of the 64 bits, resulting in a 32-bit `int` primitive being assigned to a 32-bit primitive variable.
In this particular example, there is no problem, as a value of one hundred fits with the lower 32-bits, so the set of higher thirty-two bits being excised are all zeros. So no damage in this case. But also in this case, this code is senseless, and should not be done in real work. Indeed, in real work you would only rarely, if ever, have a productive reason to lop off half of a 64-bit integer’s bits by casting.
Math.toIntExact
A better alternative to casting is to call Math.toIntExact
. You pass a long
primitive to this method, and it returns an int
, the result of narrowing the 64-bit integer to 32-bit integer. The advantage over casting is that an ArithmeticException
is thrown if overflow occurs. So you will be informed of any data loss.
try {
int x = java.lang.Math.toIntExact( 100L ) ;
} catch ( ArithmeticException e ) {
… // Handle data loss, the overflow in going from 64-bits to 32-bits.
}
Because some other Answers incorrectly raised the subject of objects and auto-boxing, I'll mention a bit about that.
The wording Long
with an uppercase L
in the front means the Long
class rather than the long
primitive. Each of the primitive types has such a wrapper class. Auto-boxing between each primitive type and its wrapper class helps to bridge the gap between these two parallel type systems. Work is underway to further smooth out the differences; see Project Valhalla.
But here and now, there is a distinction between classes/objects and primitives. To help smooth over that distinction, Java supports auto-boxing. As a convenience, in most scenarios the Java compiler and runtime can detect when your code is assigning a primitive to where an object is expected, and vice-versa.
Long myLongObject = 100L ; // This works because Java automatically detects the primitive `long` being assigned to an object of class `Long`, and instantiates a `Long` object to hold that number value.
That line above effectively is treated as if it is:
Long myLongObject = Long.valueOf( 100L ) ;
And is would be logically equivalent to the following, but technically this next line fails (compiler error) because there is no need for the L
in the string as the string is assumed to contain digits of a 64-bit integer. In other words, this input string is not an integer literal, so the L
is superfluous and not allowed.
Long myLongObject = Long.valueOf( "100L" ) ; // Compiler error. The `L` is not allowed because it is redundant.
Just drop the L
from that String input, as the input is assumed to represent a 64-bit number.
Long myLongObject = Long.valueOf( "100" ) ;
Java will also automatically widen from a 32-bit int
before also doing the autoboxing. So, the lines above are also effectively the same as this.
Long myLongObject = Long.valueOf( 100 ) ; // 32-bit `int` primitive literal automatically widened to a 64-bit `long`, then passed as argument to the `valueOf` method that takes only a `long`.
Again, the code seen in the Question has no involvement with classes/objects. This section of this Answer would be irrelevant except that other incorrect Answers raised the issues of objects & auto-boxing.
Upvotes: 15
Reputation: 362
As stated in the comments you cannot assing a long
literal to an int
variable. This is known as a narrowing primitive conversion (you can read more about it at JLS Chapter 5).
A long
will always use 64 bits to represent it's value, and an int will use 32. So assigning a long
value an int
you will lose 32 its of data since their is no space for it in the variable. The compiler will flag this as an error to protect you from potential data loss.
You can however cast a long
to an int
(eg. int a=(int)1000L;
) and the compiler will be fine with that, since you should now know that data loss may occur there.
Upvotes: 1
Reputation: 20112
long x = 100;
is an integer of 100 that will be widened to a long with all problems of integer overflow.
long x = 100L;
is an initialized long without widening.
So you will see the difference when using a number that is greather than Integer.MAX_VALUE
.
long x = 2147483648L; // will be the value that you expect it to be
long y = 2147483648; // will not compile
Upvotes: 2