byte a = 1;
byte b = 1;
byte c = a + b;
Throws error: possible loss of precision
byte subt = a_s - a_b;
^
required: byte
found: int
Is this behavior has something to do with jvm or its been defined in java language .
EDIT : And if it is defined in java language then does it because of keeping jvm in mind ?
Means if java supports byte datatype then why operation on byte results int
if java supports byte datatype then why operation on byte results int
Because that's how the Java Virtual Machine is designed. There is no instruction set to perform operation on a byte type. Rather the instruction set for int type is used for the operation on boolean, byte, char, and short types.
From JVM Spec - Section 2.11.1:
A compiler encodes loads of literal values of types byte and short using Java Virtual Machine instructions that sign-extend those values to values of type int at compile-time or run-time. Loads of literal values of types boolean and char are encoded using instructions that zero-extend the literal to a value of type int at compile-time or run-time. [..]. Thus, most operations on values of actual types boolean, byte, char, and short are correctly performed by instructions operating on values of computational type int.
The reason behind this is also specified in that section:
Given the Java Virtual Machine's one-byte opcode size, encoding types into opcodes places pressure on the design of its instruction set. If each typed instruction supported all of the Java Virtual Machine's run-time data types, there would be more instructions than could be represented in a byte. [...] Separate instructions can be used to convert between unsupported and supported data types as necessary.
For the details on what all instruction sets are available for various types, you can go through the table in that section.
There is also a table specifying the mapping of actual type to the JVM computational type:
JLS 5.6.2: Binary Numeric Promotion covers it:
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
The compiler is doing the right thing. Because (a + b) can go beyond the maximum value that can be kept in a byte variable. If you tell the compiler a, b values don't change by using the 'final' keyword it wont complain anymore.
final byte a = 1;
final byte b = 1;
byte c = a + b;
Yes,It's language spec.
The addition(+) operator. while the adding, 'a' is converts(implicitly casts) to int type,
b as well to type int. Hence result is implicitly of type int.
Same for - operator too.
Compiler is right, declare variables to final or cast to byte:
byte b = 1;
byte c = 22;
byte a = (byte) (b + c);
JAVA : byte+byte = int
:)
While doing the arithmetic operations on any operands the result is stored in this form MAX(int,operand1 type,operand2 type,...operandN type)
Ex:
byte a=10;
byte b=20;
byte c=a+b;
then result of a+b will be stored in the form of MAX(int,operand1 type,operand2 type,...operandN type)
in this case
MAX(int,byte,byte) the max value is int which is maximum so c will have the int value but c has been declared as byte, and we can't store int(bigger) value into byte(smaller). the same applies for every arithmetic operator.
that is why the error says
error: incompatible types: possible lossy conversion from int to byte
Related
If you declare variables of type byte or short and attempt to perform arithmetic operations on these, you receive the error "Type mismatch: cannot convert int to short" (or correspondingly "Type mismatch: cannot convert int to byte").
byte a = 23;
byte b = 34;
byte c = a + b;
In this example, the compile error is on the third line.
Although the arithmetic operators are defined to operate on any numeric type, according the Java language specification (5.6.2 Binary Numeric Promotion), operands of type byte and short are automatically promoted to int before being handed to the operators.
To perform arithmetic operations on variables of type byte or short, you must enclose the expression in parentheses (inside of which operations will be carried out as type int), and then cast the result back to the desired type.
byte a = 23;
byte b = 34;
byte c = (byte) (a + b);
Here's a follow-on question to the real Java gurus: why? The types byte and short are perfectly fine numeric types. Why does Java not allow direct arithmetic operations on these types? (The answer is not "loss of precision", as there is no apparent reason to convert to int in the first place.)
Update: jrudolph suggests that this behavior is based on the operations available in the JVM, specifically, that only full- and double-word operators are implemented. Hence, to operator on bytes and shorts, they must be converted to int.
The answer to your follow-up question is here:
operands of type byte and short are automatically promoted to int before being handed to the operators
So, in your example, a and b are both converted to an int before being handed to the + operator. The result of adding two ints together is also an int. Trying to then assign that int to a byte value causes the error because there is a potential loss of precision. By explicitly casting the result you are telling the compiler "I know what I am doing".
I think, the matter is, that the JVM supports only two types of stack values: word sized and double word sized.
Then they probably decided that they would need only one operation that works on word sized integers on the stack. So there's only iadd, imul and so on at bytecode level (and no operators for bytes and shorts).
So you get an int value as the result of these operations which Java can't safely convert back to the smaller byte and short data types. So they force you to cast to narrow the value back down to byte/short.
But in the end you are right: This behaviour is not consistent to the behaviour of ints, for example. You can without problem add two ints and get no error if the result overflows.
The Java language always promotes arguments of arithmetic operators to int, long, float or double. So take the expression:
a + b
where a and b are of type byte. This is shorthand for:
(int)a + (int)b
This expression is of type int. It clearly makes sense to give an error when assigning an int value to a byte variable.
Why would the language be defined in this way? Suppose a was 60 and b was 70, then a+b is -126 - integer overflow. As part of a more complicated expression that was expected to result in an int, this may become a difficult bug. Restrict use of byte and short to array storage, constants for file formats/network protocols and puzzlers.
There is an interesting recording from JavaPolis 2007. James Gosling is giving an example about how complicated unsigned arithmetic is (and why it isn't in Java). Josh Bloch points out that his example gives the wrong example under normal signed arithmetic too. For understandable arithmetic, we need arbitrary precision.
In Java Language Specification (5.6.2 Binary Numeric Promotion):
1 If any expression is of type double, then the promoted type is double, and other expressions that are not of type double undergo widening primitive conversion to double.
2 Otherwise, if any expression is of type float, then the promoted type is float, and other expressions that are not of type float undergo widening primitive conversion to float.
3 Otherwise, if any expression is of type long, then the promoted type is long, and other expressions that are not of type long undergo widening primitive conversion to long.
4 Otherwise, none of the expressions are of type double, float, or long. In this case, the promoted type is int, and any expressions that are not of type int undergo widening primitive conversion to int.
Your code belongs to case 4. variables a and b are both converted to an int before being handed to the + operator. The result of + operation is also of type int not byte
If every operand in assignment and mathematical operations, before the expression performed, promote to int (if it doesn't have L, f, d flags);
And putting an int into a smaller primitive type (such as byte) should be done with narrow-casting;
So how the following assignment works?
byte a = 100;
If 100 is an integer, so putting it into a byte needs casting.
byte a = 100;
This works because...
If the right-hand side in an assignment context is a constant expression,
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.
Where
Literals of primitive type [...]
are a constant expression.
And the range of a byte is
[...] from -128 to 127, inclusive.
byte a = 100;
This works because byte range in java is from-128 to 127,so if you assign value upto 127,there is no need for cast.
Try to assign 128,you will get compiler error.
byte a = 128 ; //compiler error(incompatible type)
byte a = (byte)128;
It's a compile-time constant, and the compiler can determine that it'll fit in a byte. This actually did require a narrowing conversion in older versions of Java.
class A {
public static void main(String [] varun) {
byte b = 65;
char ch = b;
System.out.println(ch);
}
}
Why its give an error:
possible loss of precision
required char
found byte
The error text is misleading.
A char is a 2 byte unsigned type (range 0 to 65535)
A byte is a 1 byte signed type (range -128 to 127).
Therefore a byte cannot be represented in a char in full generality (as you'll lose the negatives). So you get an error; albeit a misleading one.
Byte is 1 byte long, while char is 2 bytes long, so they are incompatible. You need to use casting:
class A
{
public static void main(String [] varun)
{
byte b = 65;
char ch = (char) b;
System.out.println(ch);
}
}
Add as explicit cast as byte just take one byte and char is of two byte in java and implicit type cast does not work with byte and char.
Use
char ch = (char) b;
Your code should be like this:
char ch = (char) b;
The error it gave you it became from the fact that a byte type is an 8-bit integers and chars is 1-bit plus the bits of encoding (UTF-8, ASCII, etc).
The difference between a byte stream and a character stream is that the character stream attempts to work with characters rather than bytes.
So a byte stream is 8-bit stream without encoding. That's why you have this error.
If You are assigned two different type of primitives to each other You may have two types of casting:
if You assign int to long, thus putting smaller type into bigger You perform widening and so called widening conversion - it is also called implicit cast
int a = 100;
long b = a;
on the other hand if You would perform conversion from long to int You are narrowing the type. Thus You need to perform explicit cast if You don't do that You get that possible loss of precision
long a = 100L;
int b = (int)a;
or as in Your case as #Bathsheba said "Therefore a byte cannot be represented in a char in full generality (as you'll lose the negatives). So you get an error; albeit a misleading one." - You need to explicitly cast so that You are aware of loosing data.
When one type of data is assigned to another type of variable, an automatic type conversion
will take place if the following two conditions are met:
• The two types are compatible.
• The destination type is larger than the source type.
When these two conditions are met, a widening conversion takes place.
So the reason for it is,
For widening conversions, the numeric types, including integer and floating-point types,
are compatible with each other. However, there are no automatic conversions from the
numeric types to char or boolean.
The conversion from a byte to a char is a so-called Widening and Narrowing Primitive Conversion (JLS 5.1.4)
First, the byte is converted to an int via widening primitive conversion (§5.1.2), and then the resulting int is converted to a char by narrowing primitive conversion (§5.1.3).
The widening conversion from byte to int is fine (both are signed), but from int to char will loose both sign and (potentially) range (as char is 0 to 65536):
A narrowing primitive conversion may lose information about the overall magnitude of a numeric value and may also lose precision and range.
And
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.
Because of this potential loss of precision, sign and informaiton you get a compilation error and an explicit cast is necessary to signal to the compiler that you know what you're doing.
This may sound too trivial for an intermediate Java programmer. But during my process of reviewing Java fundamentals, found a question:
Why is narrowing conversion like:
byte b = 13;
will be allowed while
int i = 13;
byte b = i;
will be complained by the compiler?
Because byte b = 13 ; is assignment of a constant. Its value is known at compile time, so the compiler can/should/will whine if assignment of the constant's value would result in overflow (try byte b = 123456789 ; and see what happens.)
Once you assign it to a variable, you're assigning the value of an expression, which, while it may well be invariant, the compiler doesn't know that. That expression might result in overflow and so the compiler whines.
From here:
Assignment conversion occurs when the
value of an expression is assigned
(§15.26) to a variable: the type of
the expression must be converted to
the type of the variable. Assignment
contexts allow the use of an identity
conversion (§5.1.1), a widening
primitive conversion (§5.1.2), or a
widening reference conversion
(§5.1.4). In addition, a narrowing
primitive conversion may be used if
all of the following conditions are
satisfied:
The expression is a constant expression of type byte, short, char or int.
The type of the variable is byte, short, or char.
The value of the expression (which is known at compile time, because it is a constant expression) is representable in the type of the variable.
In your example all three conditions are satisfied, so the narrowing conversion is allowed.
P.S. I know the source I'm quoting is old, but this aspect of the language hasn't changed since.
Because a literal number has no type.
Once you give it a type it must be casted to the other one:
int i = 13;
byte b = (byte) i;
A byte has 8 bits. An int, 32 bits, and it is a signed number.
Conversion from a number with a smaller range of magnitude ( like int to long or long to float ) is called widening. The goal of widening conversions is to produce no change in the magnitude of the number while preserving as much of the precision as possible. For example, converting the int 2147483647 to float produces 2.14748365e9 or 2,147,483,650. The difference is usually small, but it may be significant.
Conversely, conversion where there is the possibility of losing information about the magnitude of the number ( like long to int or double to long ) is called narrowing. With narrowing conversions, some information may be lost, but the nearest representation is found whenever possible. For example, converting the float 3.0e19 to long yields -9223372036854775807, a very different number.
If you declare variables of type byte or short and attempt to perform arithmetic operations on these, you receive the error "Type mismatch: cannot convert int to short" (or correspondingly "Type mismatch: cannot convert int to byte").
byte a = 23;
byte b = 34;
byte c = a + b;
In this example, the compile error is on the third line.
Although the arithmetic operators are defined to operate on any numeric type, according the Java language specification (5.6.2 Binary Numeric Promotion), operands of type byte and short are automatically promoted to int before being handed to the operators.
To perform arithmetic operations on variables of type byte or short, you must enclose the expression in parentheses (inside of which operations will be carried out as type int), and then cast the result back to the desired type.
byte a = 23;
byte b = 34;
byte c = (byte) (a + b);
Here's a follow-on question to the real Java gurus: why? The types byte and short are perfectly fine numeric types. Why does Java not allow direct arithmetic operations on these types? (The answer is not "loss of precision", as there is no apparent reason to convert to int in the first place.)
Update: jrudolph suggests that this behavior is based on the operations available in the JVM, specifically, that only full- and double-word operators are implemented. Hence, to operator on bytes and shorts, they must be converted to int.
The answer to your follow-up question is here:
operands of type byte and short are automatically promoted to int before being handed to the operators
So, in your example, a and b are both converted to an int before being handed to the + operator. The result of adding two ints together is also an int. Trying to then assign that int to a byte value causes the error because there is a potential loss of precision. By explicitly casting the result you are telling the compiler "I know what I am doing".
I think, the matter is, that the JVM supports only two types of stack values: word sized and double word sized.
Then they probably decided that they would need only one operation that works on word sized integers on the stack. So there's only iadd, imul and so on at bytecode level (and no operators for bytes and shorts).
So you get an int value as the result of these operations which Java can't safely convert back to the smaller byte and short data types. So they force you to cast to narrow the value back down to byte/short.
But in the end you are right: This behaviour is not consistent to the behaviour of ints, for example. You can without problem add two ints and get no error if the result overflows.
The Java language always promotes arguments of arithmetic operators to int, long, float or double. So take the expression:
a + b
where a and b are of type byte. This is shorthand for:
(int)a + (int)b
This expression is of type int. It clearly makes sense to give an error when assigning an int value to a byte variable.
Why would the language be defined in this way? Suppose a was 60 and b was 70, then a+b is -126 - integer overflow. As part of a more complicated expression that was expected to result in an int, this may become a difficult bug. Restrict use of byte and short to array storage, constants for file formats/network protocols and puzzlers.
There is an interesting recording from JavaPolis 2007. James Gosling is giving an example about how complicated unsigned arithmetic is (and why it isn't in Java). Josh Bloch points out that his example gives the wrong example under normal signed arithmetic too. For understandable arithmetic, we need arbitrary precision.
In Java Language Specification (5.6.2 Binary Numeric Promotion):
1 If any expression is of type double, then the promoted type is double, and other expressions that are not of type double undergo widening primitive conversion to double.
2 Otherwise, if any expression is of type float, then the promoted type is float, and other expressions that are not of type float undergo widening primitive conversion to float.
3 Otherwise, if any expression is of type long, then the promoted type is long, and other expressions that are not of type long undergo widening primitive conversion to long.
4 Otherwise, none of the expressions are of type double, float, or long. In this case, the promoted type is int, and any expressions that are not of type int undergo widening primitive conversion to int.
Your code belongs to case 4. variables a and b are both converted to an int before being handed to the + operator. The result of + operation is also of type int not byte