I have read a section about literals and how they are used. For example you would add l or L at the end of a number to denote that the int is a long type. Same goes with the floating point numbers (f or F and d or D). What is the point of distinguishing this character at the end of a number. When we give the type does it not already know why specify again? So, what exactly is the point of adding this character to the end of a number? Where is it being used?
I have tried searching these questions on google and stack overflow already, but have not been able to receive a well developed answer to it.
The compiler knows how to treat the final result of an expression, but the individual literals (or variables) in an expression each have their own types, as do the intermediate values in the expression. For example:
static final double HALF = 1 / 2;
will actually have the value zero, because the literal 1 and 2 are int-typed, the division is an integer division that produces an int value of zero, and then Java turns that into a double. In contrast, in the expression
static final double HALF = 1d / 2;
the compiler knows to treat the first value as a double. The second value is promoted, Java does floating-point division, and the result is 0.5 as expected.
There are other situations, like autoboxing, where the compiler may treat equivalent values differently depending on their types; when passed to a method that takes an Object, 0 is an Integer, while 0L is a Long. This sort of situation occurs frequently in persistence/DAO code. Also, when compiling, the compiler evaluates compile-time constant expressions and puts their values directly into the code. The values of float and double expressions may be different because of the differing precisions of the types, and so you need to specify if you want a floating-point expression treated as just a float instead of as a double (the default).
You can not use a value greater than 2147483647 anywhere in java unless you have appended L or D to it. l makes the literal long type and d makes the literal double type.
e.g. System.out.println(2147483648); will result in an error as well as
long num=2147483650; will also result in an error as these literals are no longer int type which the default type for the integers. So by appending l or d to a number you can use it as int or double type.
Related
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.
This question already has answers here:
Reasoning behind having to specify L for long, F,D for float, double
(3 answers)
Closed 8 years ago.
When I execute this code in java:
long l = 999_999_999_999;
I get the following error,
error: integer number too large: 999999999999
long l = 999_999_999_999;
But if I explicitly specify the number as long by adding l or L at the end, the problem disappears.
long l = 999_999_999_999L; // Works
My question is, why?
I know that all integral literals in java are integer by default, but why it would stop java from type casting and accommodating the value in a long, when a long is clearly large enough to hold the literal?
I am looking for some technical details.
This is perfectly intended.
Think about how the program is parsed. The lexer which splits the Java source into tokens knows about two things of literal:
the ones which don't end with [L|l]
the ones which end with [L|l]
A literal which doesn't have the long specifier at the end is parsed as an integer. This means that the literal itself is invalid because you are not allowed to define an integer literal which is larger than the larger number that you can represent with an int.
This is clear in the grammar specification here:
An integer literal is of type long if it is suffixed with an ASCII letter L or l (ell); otherwise it is of type int (§4.2.1).
It is a compile-time error if a decimal literal of type int is larger than 2147483648 (231), or if the decimal literal 2147483648 appears anywhere other than as the operand of the unary minus operator (§15.15.4).
So even without any assignment, if you have the expression
999_999_999_999
This is parsed as an integer literal, but its value is over the maximum allowed value, hence it is illegal. The fact that the value of this expression is later assigned to something is irrelevant.
Java won't automatically cast your int literal as a long, because the int literal is invalid in the first place. That's why long literals exist, so values greater in magnitude can be expressed as literals.
According to the JLS, Section 3.10.1:
It is a compile-time error if a decimal literal of type int is larger than 2147483648 (231), or if the decimal literal 2147483648 appears anywhere other than as the operand of the unary minus operator (§15.15.4).
In Java, you simply can't have an int literal bigger than Integer.MAX_VALUE, even if its only use is to assign a value to a long. Bigger literals must be long with an L suffix to begin with.
If your going to understand your problem. You will have to understand how Java reads and assign values to variables.
Java first reads the value that you want to assign to the variable, which is "99999999" then assigns it to the variable.
Without the "L" at the end, Java reads the value of the number, but encounters the problem that it is too big for an int. with the "L" at the end, Java knows it is a Long, therefore it is large enough.
1.when we assign double to float variable compiler gives us error
float f = 2753.2211;
possible loss of precision Required to cast.
2.when we assign int to byte variable compiler don't gives us error
byte b = 24;
OK
In second case data can also be lost.Then why casting explicitly is not necessary.?
The second case is explicitly allowed by the JLS as a special case. In JLS 5.2, which deals with narrowing conversions, it says:
In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:
A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.
...
In other words, for the non-long integer-like values, you can implicitly narrow them iff the value you're narrowing is a constant that fits within the type you're specifying.
I'm guessing the same trick isn't applied to floats because floating point values are trickier than integer values. For instance, 0.1 can't be exactly expressed in a floating point, while 1.0 can. That means that double d = 0.1 isn't actually putting the value 0.1 into d -- just a value that's very close to 0.1. Given that, the "does it fit exactly" rule doesn't apply even to floating point literals, and the question of "does it fit exactly when we narrow" becomes trickier. Your options would basically be:
always allow it (which could cause some surprising behavior if a value is significantly different than its literal representation)
only allow it if the value can be exactly put in. This would look highly inconsistent:
float f1 = 1.0 and double d1 = 1.0 both work
double d2 = 0.1 works, but float f2 = 0.1 doesn't -- confusing!
never allow it (slightly inconvenient, because you have to type the f char in the literal)
Given these options, it seems that the designers of the JLS chose the least of three not-great options.
Data isn't going to be lost in the second case.
A byte comprises the values of -128 and 127 inclusive, so as long as your int fits within that range, no loss of precision can occur.
Your second value is not a float-literal; by default, all floating point values in Java are double. You can explicitly make that a float by adding f to the end of it.
float f = 2573.2211f;
int is a 32-bit signed integer, byte is an 8-bit signed integer. A byte runs from -128 to 127, while a int runs from -2147483648 to 2147483647
Precision isn't lost, but do not cast a big int into a small byte or you will lose data.
I can easily read 2e15 as "two quadrillion" at a glance, but for 2000000000000000 I have to count the zeroes, which takes longer and can lead to errors.
Why can't I declare an int or long using a literal such as 2e9 or 1.3e6? I understand that a negative power of 10, such as 2e-3, or a power of 10 that is less than the number of decimal places, such as 1.0003e3, would produce a floating point number, but why doesn't Java allow such declarations, and simply truncate the floating-point part and issue a mild warning in cases where the resulting value is non-integral?
Is there a technical reason why this is a bad idea, or is this all about type-safety? Wouldn't it be trivial for the compiler to simply parse a statement like
long x = 2e12 as long x = 2000000000000 //OK for long
and int y = 2.1234e3 as int y = 2123.4 //warning: loss of precision
It's because when you use the scientific notation you create a floating point number (a double in your example). And you can't assign a floating point to an integer (that would be a narrowing primitive conversion, which is not a valid assignment conversion).
So this would not work either for example:
int y = 2d; //can't convert double to int
You have a few options:
explicitly cast the floating point to an integer: int y = (int) 2e6;
with Java 7+ use a thousand separator: int y = 2_000_000;
Because it's a shortcoming of Java.
(Specifically, there is clearly a set of literals represented by scientific notation that are exactly represented by ints and longs, and it is reasonable to desire a way to express those literals as ints and longs. But, in Java there isn't a way to do that because all scientific notation literals are necessarily floats because of Java's language definition.)
You are asking about the rules on writing a integer literals. See this reference:
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
The capability to use scientific notation as an integer literal might make things easier indeed but has not been implemented. I do not see any technical reason that would prevent such a feature from being implemented.