I am working with data types at the moment in Java, and if I have understood correctly the type long accepts a value between the ranges of -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807. Now as you can see below, I have create a long variable called testLong, although when I insert 9223372036854775807 as the value, I get an error stating:
The literal 9223372036854775807 of the type int is out of range.
I don't know why it is referring to the long data type as an int.
Anyone have any ideas?
Code:
char testChar = 01;
byte testByte = -128;
int testInt = -2147483648;
short testShort = -32768;
long testLong = 9223372036854775807;
float testFoat;
double testDouble = 4.940656458412;
boolean testBool = true;
Add a capital L to the end:
long value = 9223372036854775807L;
Otherwise, the compiler will try to parse the literal as an int, hence the error message
I don't know why it is referring to the long data type as an int
It is not. You should learn to trust compiler messages (especially when they are from sane, modern compilers and not ancient compilers that tended to have bad error messages). While the language that they speak might be hard to decipher at times, they are not usually lying to you.
Let's look at it again:
The literal of int 9223372036854775807 is out of range.
Note, that it doesn't mention your variable testLong or the type long anywhere, so the problem is not about the initialization. It seems to occur at some other point.
Now lets investigate some of the parts of the message:
int tells us that he wants to treat something as an int value (which is not what you wanted!)
"out of range" is pretty clear: something is not within the expected range (probably that of int)
"The literal": now that's interesting: what is a literal?
I'll leave the cozy list to talk about literals for a moment: literals are places where you have some value in your code. There are String literals, int literals, class literals and so on. Every time you mention a value explicitly in your code, it's a literal.
So it's not actually nagging you about the variable declaration, but the number itself, the value is what it's nagging you about.
You can easily verify this by using the same literal in a context where a long and an int are equally acceptable:
System.out.println(9223372036854775807);
PrintStream.println can take either an int or a long (or pretty much anything else). So that code should be fine, right?
No. Well, maybe it should be, but according to the rules it is not fine.
The problem is that "some digits" is defined to be an int literal and therefore must be in the range defined by int.
If you want to write a long literal, then you must make that explicit by appending the L (or lower case l, but I highly suggest you always use the upper-case variant, because it's much easier to read and harder to mistake for a 1).
Note that a similar problem occurs with float (postfix F/f) and double (postfix D/d).
Side note: you'll realize that there are no byte or short literals and you can still assign values (usually int literals) to byte and short variables: that's possible due to special rules in § 5.2 about conversions in an Assignment Contexts: they allow assignment of constant expressions of a larger type to byte, short, char or int if the values are within the types range.
Try doing 9223372036854775807L. The L at the end tells Java that 9223372036854775807 is a long.
I had this problem in the past and I fixed that by writing the value in the scientific form.
for example:
double val = 9e300;
long ak = 34778754226788444L/l;
Both use but at a time only one use uppercase L or lowercase l.
Why use L/l? Because long is a part of integral datatype.
Related
Why are the "F" and "L" suffixes needed when declaring a long or float? According to the documentation:
An integer literal is of type long if it ends with the letter L or l; otherwise it is of type int.
A floating-point literal is of type float if it ends with the letter F or f; otherwise its type is double.
So, from that, obviously the compiler is treating the values as either an int data type or a double data type, by default. That doesn't quite explain things for me.
I dug a bit deeper and found a discussion where a user describes the conversion from a 64-bit double into a 32-bit float would result in data loss, and the designers didn't want to make assumptions.
Questions I still have:
Why would the compiler allow one to write byte myByte = 100;, and the compiler automatically convers 100, an int as described above, into a byte, but the compiler won't allow the long myLong = 3_000_000_000;? Why will it not auto-convert 3_000_000_000 into a long, despite it being well within the range of a long?
As discussed above, when designing Java, the designers won't allow a double to be assigned to a float because of the data loss. While this may be true for a value that is outside of the range of a float, obviously something like 3.14 is small-enough for a float. So then, why does the compiler throw an error with the assignment float myFloat = 3.14;?
Ultimately, I'm failing to fully understand why the suffixes are needed, and the rules surrounding automatic casting (if that's what's happening under-the-hood), etc.
I know this topic has been discussed before, but the answers given only raise more questions, so I am deciding to create a new post.
In answer to your specific questions:
The problem with long myLong = 3_000_000_000; is that 3_000_000_000 is not a legal int literal because 3,000,000,000 does not fit into 4 bytes. The fact that you want to promote it to a long in order to initialize myLong is irrelevant. (Yes, the language designers could have designed the language so that in this context 3_000_000_000 could have been parsed as a long, but they didn't, probably to keep the language simpler and to avoid ambiguities in other contexts.)
The problem with 3.14 is not a matter of range but of loss of precision. In particular, while 3.14 terminates in base 10 representation, it does not have a finite representation in binary floating point. So converting from a double to a float (in order to initialize myFloat) would involve truncating significant, non-zero bits of the representation. (But just to be clear: Java considers every narrowing conversion from double to float to be lossy, regardless of the actual values involved. So float myFloat = 3.0; would also fail. However, float myFloat = 3; succeeds because conversion from an int value to a float is considered a widening conversion.)
In both cases, the right thing to do is to indicate exactly to the compiler what you are trying to do by appending the appropriate suffix to the numeric literal.
Why would the compiler allow one to write byte myByte = 100;, and the compiler automatically convers 100, an int as described above, into a byte, but the compiler won't allow the long myLong = 3_000_000_000;?
Because the spec says so. Note that byte myByte = 100; does work, yes, but that is a special case, explicitly mentioned in the Java Language Specification; ordinarily, 100 as a literal in a .java file is always interpreted as an int first, and never silently converts itself to a byte, except in two cases, both explicitly mentioned in the JLS: The cast is 'implied' in modified assignment: someByteArr += anyNumber; always works and implies the cast (again, why? Because the spec says so), and the same explicit presumption is made when declaring a variable: byte b = 100;, assuming the int literal is in fact in byte range (-128 to +127).
The JLS does not make an explicit rule that such concepts are applied in a long x = veryLargeLiteral;. And that is where your quest really ought to end. The spec says so. End of story.
If you'd like to ask the question: "Surely whomever person or persons added this, or rather failed to add this explicit case to the JLS had their reasons for it, and these reasons are more technical and merit based than 'cuz they thought of it in a dream' or 'because they flipped a coin', and then we get to a pure guess (because you'd have to ask them, so probably James Gosling, about why he made a decision 25 years ago):
Because it would be considerably more complex to implement for the javac codebase.
Right now literals are first considered as an int and only then, much later in the process, if the code is structured such that the JLS says no cast is needed, they can be 'downcast'. Whereas with the long scenario this does not work: Once you try to treat 3_000_000_000 as an int, you already lost the game because that does not fit, thus the parser that parses this needs to create some sort of bizarro 'schrodinger's cat' style node, which represents 3_000_000_000 accurately, but nevertheless will downstream get turned into a parsing error UNLESS it is used in an explicit scenario where the silently-treat-as-long part is allowed. That's certainly possible, but slightly more complex.
Presumably the same argument applies to why, in 25 years, java has not seen an update. It could get that at some point in time, but I doubt it'll have high priority.
As discussed above, when designing Java, the designers won't allow a double to be assigned to a float because of the data loss.
This really isn't related at all. int -> long is lossy, but double -> float mostly isn't (it's floating point, you lose a little every time you do stuff with them pretty much, but that's sort of baked into the contract when you use them at all, so that should not stop you).
obviously something like 3.14 is small-enough for a float.
Long and int are easy: Ints go from about -2 billion to about +2 billion and longs go a lot further. But float/double is not like that. They represent roughly the same range (which is HUGE, 300+ digit numbers are fine), but their accuracy goes down as you get away from the 0, and for floats it goes down a lot faster. Almost every number, probably including 3.14, cannot be perfectly represented by either float or double, so we're just arguing on how much error is acceptable. Thus, java does not as a rule silently convert stuff to a float, because, hey, you picked double, presumably for a reason, so you need to explicitly tell the compiler: "Yup. I get it, I want you to convert and I will accept the potential loss, it is what I want", because once the compiler starts guessing at what you meant, that is an excellent source of hard to find bugs. Java has loads of places where it is designed like this. Contrast to languages like javascript or PHP where tons of code is legal even if it is bizarre and seems to make no sense, because the compiler will just try to guess at what you wanted.
Java is much better than that - it draws a line; once your code is sufficiently weird that the odds that javac knows what you wanted drop below a treshold, java will actively refuse to then take a wild stab in the dark at what you meant and will just flat out refuse and ask you to be more clear about it. In a 20 year coding career I cannot stress enough how useful that is :)
I know this topic has been discussed before, but the answers given only raise more questions, so I am deciding to create a new post.
And yet you asked the same question again instead of the 'more questions' than this raised. Shouldn't you have asked about those?
First, we need to understand how declaration happens in Java. Java is a statically-typed language, once we declare a variable, we can't change the data type of our variable after. Let's look up an examples:
long myLong = 3_000_000_000;
Integral types(byte,short,int,long) are "int" by default. The differences are sizes(byte<short<int<long).
When we declare a variable we're saying to java that "myLong" variable's type should be long(which is int but longer size). And after we're trying to equalize with "3_000_000_000"(Literal) which is int BUT int's max value is 3,147,483,647 so it's bigger. That's why we should write "L or l" to the end of the literal. After adding "l", now, our literal is long and we can equalize with declared long "myLong". => long myLong = 3_000_000_000l;
int myInt = 300L; => (Error will appears)
In this example our literal(300L) is long. As I mentioned before long's size is bigger than other integral types. When we delete "L" from end of the literal, "300" will be int.
Here is another example for FLoat and Double :
float myFloat = 5.5; (Error)
float myFloat = 5.5F; (Correct version)
Float and Double are "double" by default. The difference is, double bigger than float. myFloat is "float" in the begining, 5.5 is double so error will appear that we can't equalize. That is why we should add "F or f" to the end of the 5.5. We can use "D or d" for double but it's up on us, it's not necessary because there's no bigger floating type than double.
Hope it's clear :)
System.out.println(2147483647 + 1); //prints -2147483648
I know 2147483647 is the max value of integer data type. My question is why is this result calculated for Integer type, and why was it not considered for Long or double?
Because...
System.out.println(127+1); //prints 128
here why is 127 not considered for Byte data type, resulting in the result to be -128?
Fundmentally, you seem to not fully understand literals. A number without a decimal point or suffix is always an int, regardless of it's magnitude. This can be further complicated by implicit widening when assigning to larger primitive datatypes (e.g. int may be implicitly widened to long).
So now we know that your two literals are ints. int + int is always int. It doesn't matter whether the result will overflow or not.
If you know or suspect that the constants will exceed the range of int, add the suffix L (i.e. 2147483647L and 1L) to explicitly declare that these are longs. long + long = long, so the result will not overflow in this case.
println is overloaded with several inputs, your paramters are of type int so method will be called
public void print(int i) {
write(String.valueOf(i));
}
Every number in java sorce code is by default an integer. If you like to have an other type like long, you need to extend your number with an 'L' (e.g. 23409L) or you have to cast it. Only at initialization from a variable the compiler make the cast for you.
In many cases you can give byte or short also to methodes, even if they request for an integer parameter. But this only works because of java's conversions and promotions mechanism.
Because of all this functionalities some programmer mess up with the real data types they have at one point of the code.
For more infos visit the oracle documentation:
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html
I know that numeric literals in Java are by default of the type int.
So the 5 in the following example actually is an int as long as I don't write an 'L' behind it. So why can't I assign the result of a*b back to an int variable, if 5 and 7 are both of the type int?
long a = 5;
int b = 7;
int c = a * b;
I do not understand why Java has problems seeing something like this as long:
long a = 345236577970;
but still performs a typecast if the expression includes a long variable, even though its type is actually int. Super basic beginner question, sorry.
Your reasoning is that 5 and 7 (both int) are assigned to variables which are then multiplied so the result should be an int. The flaw in this reasoning is that your code is not multiplying 5 and 7, but a and b. Once constants are assigned to these variables it's irrelevant what the type of the constant is: the only thing that matters is the type of the variable. In this case the types are long and int so the result is a long.
Simple options to convert to int is to cast or to use Math.toIntExact
Before the computation is done, there's no way to know what the result will be (which seems obvious but sometimes needs to be said out loud). It could be a result that could fit in an int, but it might not be -- it could be a long. So the language is designed to require that the result be of a type that could fit the largest possible range of results.
If you want to stuff the final result back into an int, you can certainly cast it into an int variable, but you do open yourself up to the risk that the result might not fit in there.
I am working with data types at the moment in Java, and if I have understood correctly the type long accepts a value between the ranges of -9,223,372,036,854,775,808 to +9,223,372,036,854,775,807. Now as you can see below, I have create a long variable called testLong, although when I insert 9223372036854775807 as the value, I get an error stating:
The literal 9223372036854775807 of the type int is out of range.
I don't know why it is referring to the long data type as an int.
Anyone have any ideas?
Code:
char testChar = 01;
byte testByte = -128;
int testInt = -2147483648;
short testShort = -32768;
long testLong = 9223372036854775807;
float testFoat;
double testDouble = 4.940656458412;
boolean testBool = true;
Add a capital L to the end:
long value = 9223372036854775807L;
Otherwise, the compiler will try to parse the literal as an int, hence the error message
I don't know why it is referring to the long data type as an int
It is not. You should learn to trust compiler messages (especially when they are from sane, modern compilers and not ancient compilers that tended to have bad error messages). While the language that they speak might be hard to decipher at times, they are not usually lying to you.
Let's look at it again:
The literal of int 9223372036854775807 is out of range.
Note, that it doesn't mention your variable testLong or the type long anywhere, so the problem is not about the initialization. It seems to occur at some other point.
Now lets investigate some of the parts of the message:
int tells us that he wants to treat something as an int value (which is not what you wanted!)
"out of range" is pretty clear: something is not within the expected range (probably that of int)
"The literal": now that's interesting: what is a literal?
I'll leave the cozy list to talk about literals for a moment: literals are places where you have some value in your code. There are String literals, int literals, class literals and so on. Every time you mention a value explicitly in your code, it's a literal.
So it's not actually nagging you about the variable declaration, but the number itself, the value is what it's nagging you about.
You can easily verify this by using the same literal in a context where a long and an int are equally acceptable:
System.out.println(9223372036854775807);
PrintStream.println can take either an int or a long (or pretty much anything else). So that code should be fine, right?
No. Well, maybe it should be, but according to the rules it is not fine.
The problem is that "some digits" is defined to be an int literal and therefore must be in the range defined by int.
If you want to write a long literal, then you must make that explicit by appending the L (or lower case l, but I highly suggest you always use the upper-case variant, because it's much easier to read and harder to mistake for a 1).
Note that a similar problem occurs with float (postfix F/f) and double (postfix D/d).
Side note: you'll realize that there are no byte or short literals and you can still assign values (usually int literals) to byte and short variables: that's possible due to special rules in § 5.2 about conversions in an Assignment Contexts: they allow assignment of constant expressions of a larger type to byte, short, char or int if the values are within the types range.
Try doing 9223372036854775807L. The L at the end tells Java that 9223372036854775807 is a long.
I had this problem in the past and I fixed that by writing the value in the scientific form.
for example:
double val = 9e300;
long ak = 34778754226788444L/l;
Both use but at a time only one use uppercase L or lowercase l.
Why use L/l? Because long is a part of integral datatype.
Consider following statement:
byte by = 5; //works fine
literal '5' is of type int and small enough to fit into a variable of type byte. Compiler does the implicit type casting here (from int to byte).
Now consider following scenario:
float fl = 5.5; //compilation error
literal '5.5' is of type double, also small enough to fit into a variable of
type float. Why do we need to explicitly type cast like this:
float fl = (float) 5.5; //works fine
Why compiler is not doing the casting for us in case of floating points?
In the integer version, the compiler knows that all the data in the number 5 can be stored in a byte. No information is lost. That's not always true for floating point values. For example, 0.1f isn't equal to 0.1d.
Now for the example, you've given, the decimal value 5.5 is exactly represented in both float and double, so you could argue that in that case, no information is lost - but it would be pretty odd for the language specification to have to make this valid:
float f = 5.5;
but this invalid:
float f = 5.6;
The language specification is happy to talk about whether a number fits within the range of float/double (although even that isn't as simple as you might expect) but when it comes to whether a literal can be exactly represented, I don't think it ever goes into detail.
The easy answer is, because the specification says so (compile-time constants of type integer can be assigned to smaller types as long as they fit).
With floating-point however, there is not so much determining whether the constant fits, but rather the loss of precision that comes along with it. E.g. assigning 1.23456789123 to a double is fine, but to a float is not. It's not so obvious why, in this case, though, at least to some programmers. I'd definitely count it as a surprise when some floating-point constants work while others won't and the reason isn't as clear as with integral types (where the limits are often second nature to most).
Note that even with doubles there sometimes is lost information. You can make your constants as precise as you want, but you won't always get the exact value you stated in the variable.
Agreed with Jon, However, I would like to add that
byte by = 5; //works fine until the number is less than 128
This is because one byte can only hold upto -128 to 127. Once you will try to enter number above 127, you will get the same error like you get when storing double value into float.
byte by = 128; //compilation error
So for agreeing the lost of the conversion data, you need to perform the explicit conversion.
byte by = (byte) 128; // work fine
Perhaps the most significant reason that Java makes allowance for implicit narrowing conversions of literals of type int to short and byte, but does not do so for conversions of literal double values to float is that Java includes float literals, but does not allow literals of types byte and short.
Personally, I really dislike Java's numerical conversion rules, but the allowance for storing integer constants to short and byte makes those types at least somewhat bearable.