I understand that "2.5" is automatically a double, and to make it a float, I need to do "2.5F" (or should the F be lowercase?), and that I should use a float, say, if I had a constant that only ever needed 2 decimal spaces (like "0.08F" for Ontario PST tax), but I'm not sure whether "12" is an int or a long, but I know "12L" is a long, but "long l = 12" and "long l = 12L" seem to compile to the same thing, and I use long's if I want maximum non-floating point precision, and int if I know I won't need beyond int's limits.
Please correct me if there's something there that isn't right, and answer the quesions I have.
12 as a constant in java is an int.
The reason long l = 12 compiles is that it is automatically widened to a long.
EDIT: Regarding your comment, there is nothing wrong with automatic widening, use whatever makes your code clearer, but just be aware of what is going on when you do math on primitives. For example:
int i = 1213;
long l = 112321321L * i;
The long will have a very different value if you don't explicitly put that first number as a long because Java will treat it as integer math, and cause an overflow.
It doesn't make a difference if you use lower or upper case when declaring your floats .
...like "0.08F" for Ontario PST tax
If you are using these fields for currency, you should consider using BigDecimal instead. See this explanation and its related links from Sun for more detail.
First, 12 is an int. Since you didn't specify a type, the compiler assumes int, just as it assumes double when you don't specify a type for 2.5.
The assignment
long x = 12;
compiles just fine because there is no loss of precision when the compiler implicitly upcasts the literal int value 12 to a long.
I always try to use uppercase type specifiers like 2.5F and 12L, simply because they're easier to read. 1 and l look much the same in the monospaced font that I prefer.
Note that while int literals will be auto-widened to long when assigning to a long variable, you will need to use an explicit long literal when expressing a value that is greater than Integer.MAX_VALUE (2147483647) or less than Integer.MIN_VALUE (-2147483648):
long x1 = 12; //OK
long x2 = 2147483648; // not OK! That's not a valid int literal
long x3 = 2147483648L; // OK
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.
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.
I was basically playing with data types in order to learn java and here is what i am confused about.
double douVar = 30000000000.323262342134353;
int intVar = (int)douVar; // casting
System.out.println(intVar);
Now converting the douVar to string i overwrite the double variable:
douVar = 345839052304598; // returns an error: Integer number too long
System.out.println(Double.toString(douVar));
complete error:
Error:(20, 18) java: integer number too large: 345839052304598
I'm using IntellijIDEA compiler. I didnt try this over eclipse though but i assume the compiler would not be so different.
Does this mean that casting would result in modifying the original variable as well?
In Java, constant numbers without a decimal are ints by default.
There are 2 ways to change the constant definition to a double:
Add a d or D at the end.
Add a .0 at the end
douVar = 345839052304598d;
douVar = 345839052304598.0;
Java interprets 345839052304598 as an integer.
In Java an Integer is 4 bytes long and therefore has a value range from –2 147 483 648 to 2 147 483 647. (your number is obviously not in that range)
To make Java treat the number as a double, you must write:
double d = 345839052304598D;
/* or */
double d1 = 345839052304598.0;
(Same goes for a long, you have to write L instead of D in that case)
The literal 345839052304598 will be considered as an integer by the compiler, since this value is to large for an integer, a compile time error is thrown. Therefore you need to tell the compiler that the value you want to use is actually double value, that you can do the following way:
douVar =345839052304598D; // note D at the end which tells comipler that it is double
When you declare number as 345839052304598 compiler tries to read it as a 32 bit integer. But since this exceed the range of int compiler throws the error.
You can use d, D or L suffix or add decimal place like .0 to to handle this,
Just change douVar = 345839052304598; to douVar = 345839052304598.00;