Strange typecast while doing variableOfTypeA+=variableOfTypeB - java

I am using Java and new to it.
When I try
int integerValue = 100;
long longValue = 100;
integerValue = integerValue + longValue;
I get "Type mismatch: cannot convert from long to int".
But
integerValue+=longValue;
works fine, which means it is doing the cast for me :)
Is it something that "+=" provides inherently? Any specific reason for that?
Edit: Oops!! Too common question! :) I should have thoroughly searched first, my bad!!

Yes, this is behaving exactly as section 15.26.2 of the JLS explains.
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

You have uncovered the Tweedledum puzzle from the Java Puzzlers book.
Basically the compound assignment performs type cast and regular one doesn't. See JLS for details.

Using the operation assignment operators, there is an implicit cast.
int i = 10;
i *= 5.5;
// same as
i *= (int) (i * 5.5);
or even
char ch = '5';
ch /= 1.1; // ch = '0'

That's correct. In your first example, you have to cast to int, because the result result of the left expression is a long value (only because longValue is long).
integerValue = (long) (integerValue + longValue); // this works
The += operator does the (same) casting implicity.
Both behaviours are specified in the Java Language Specification.

Thanks everyone!
All answers were good enough!
Better explanations and examples available at stackoverflow.com/questions/8710619/java-operator :)

Related

Cannot resolve method equals(java.lang.Long)

The following code gives error (with IDEA) while I think it shouldn't.
Long[] a = {0L, 0L};
Long[] b = {1L, 1L};
if((a[0] + a[1]).equals(b[1]))
System.out.println("Equal");
Says cannot resolve method equals(java.lang.Long). But it works well with if(a[0].equals(b[0])). I thought that plus operator would return a Long object.
Why does it seem like it doesn't return a Long object, and how are we able to use Long c = a[0] + a[1] if it doesn't return a Long object? Or why can't we use equals like that?
Why does it seem like it doesn't return a Long object?
15.18.2. Additive Operators (+ and -) for Numeric Types tells us that:
Binary numeric promotion is performed on the operands.
The type of an additive expression on numeric operands is the promoted type of its operands.
And 5.6.2. Binary Numeric Promotion tells us that:
If any operand is of a reference type, it is subjected to unboxing conversion.
What this means is that the result of Long + Long is long and we can't call methods on a primitive type.
And how are we able to use Long c = a[0] + a[1] if it doesn't return a Long object?
For Long c = a[0] + a[1], the long is boxed by the assignment.
a[0] + a[1] are added as primitive types and are not autoboxed (primitives do not have methods, hence compile time error). You need to either explicitly wrap them into an object:
(new Long(a[0] + a[1])).equals(b[1])
...or rely on the unboxing of b[1] into a primitive type
a[0] + a[1] == b[1]
(a[0] + a[1])
results in primitive long and not in reference type java.lang.Long.
If you're trying to use a member of a primitive type, that results in a compile time error.
You could use autoboxing, to convert the result of the addition back to Long like this:
((Long)(a[0] + a[1])).equals(b[1])
Long c = (a[0] + a[1]); does something like that "internally", i.e. actually works like this:
Long c = (Long)((long)a[0] + (long)a[1]);
You could also simply unbox b[1]:
(a[0] + a[1]) == b[1]
All you need to do is replace this line:
if((a[0] + a[1]).equals(b[1]))
for this:
if(a[0] + a[1] == b[1])
EDIT:
Yes, you're right - equals can't take sum of longs as parameter, from other answers I can see that it's because they are primitive values. Good to know that, we learn everyday :)

Type mismatch: cannot convert from long to int

I had the following lines of code
long longnum = 555L;
int intnum = 5;
intnum+=longnum;
intnum= intnum+longnum; //Type mismatch: cannot convert from long to int
System.out.println("value of intnum is: "+intnum);
I think line-3 and line-4 do same task,
then why compiler showing error on line-4 "Type mismatch: cannot convert from long to int"
please help.
That's because the compound assignment operator does implicit casting.
From JLS Compound Assignment Operator:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
While in case of binary + operator, you have to do casting explicitly. Make your 4th assignment:
intnum = (int)(intnum+longnum);
and it would work. This is what your compound assignment expression is evaluated to.
I think line-3 and line-4 do same task, then why compiler showing error on line-4 "Type mismatch: cannot convert from long to int"
Because they don't do the same thing. Compound assignment operators have an implicit cast in them.
From section 15.26.2 of the JLS:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
So your third line is more like:
intnum = (int) (intnum + longnum);
The cast is required because in the expression intnum + longnum, binary numeric promotion is applied before addition is performed in long arithemtic, with a result of long. There's no implicit conversion from long to int, hence the cast.
Long id = 50;
Integer sum = Integer.valueOf(Long.toString(id));

Java += compiler/jre bug? [duplicate]

This question already has answers here:
Why don't Java's +=, -=, *=, /= compound assignment operators require casting?
(11 answers)
Closed 9 years ago.
I encountered someting unexpected with the java += operator.
Apparently, this compiles:
int a = 0;
a += 3/2.0;
System.out.println(a); // outputs "1"
While, this doesn't
int a = 0;
a = a + (3/2.0); // eclipse compiler error "Type mismatch: cannot convert from double to int"
System.out.println(a);
Is this expected behaviour? I find it strange that the += operator does not report a "Type mismatch", because it is an 'add and assign' operator, where you add a double, which gives a double result, and is then assigned to an int variable. Instead it silently casts (and truncates) the result.
This is the way += has worked from C. It's "feature" not a bug
See Java's +=, -=, *=, /= compound assignment operators
BTW You can try this
char ch = '0';
ch *= 1.1; // ch = '4'
Also see a post of mine http://vanillajava.blogspot.com/2012/11/java-and-implicit-casting.html
int a = a + (3/2.0); doesn't compile since:
int + double leads to a double
a is referenced as an int
cast from double to int missing
int a += 3/2.0; compiles since:
int + double leads to a double
a is referenced as an int
double is castable to an int and luckily, compiler adds an implicit cast similar to:
int a = (int)(a+ 3/2.0);. This is due to the special op= notation that is interpreted more cleverly from compiler than the basic assignment operator: =.
This is not a bug , its a implicit conversion happened.
for eg.
Byte b=3;
b+=5; //compiles
b=b+5; //doesnt compiles
Here what happens is
a=a+3/2.0; // 3/2.0 produces double , it add int to double but cant convert it implicitly to int.
a += 3/2.0; // here implicit conversion after addition of a to 3/2.0 happends from double to int

Interesting observation on byte addition and assignment

Today while helping someone I came across an interesting issue which I couldn't understand the reason.
While using += we don't need to explicit casting, but when we use i+i, we need to explicitly cast. Couldn't find exact reason. Any input will be appreciated.
public class Test{
byte c = 2;
byte d = 5;
public void test(String args[])
{
c += 2;
d = (byte) (d + 3);
}
}
Java is defined such that += and the other compound assignment operators automatically cast the result to the type of the variable being updated. As a result, the cast isn't necessary when using +=, though it is necessary when just using the normal operators. You can see this in the Java Language Specification at http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.26.2
Specifically, the expression
a op= b
Is equivalent to
(a = (type of a)((a) op (b));
Hope this helps!
From the Java Language Spec, Chapter 15:
[..] the result of the binary operation (Note: (c+2) in our example, which results in an int type value) is converted to the type of the left-hand variable (Note: to byte in our example), subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.

Java - short and casting

I have the following code snippet.
public static void main(String[] args) {
short a = 4;
short b = 5;
short c = 5 + 4;
short d = a;
short e = a + b; // does not compile (expression treated as int)
short z = 32767;
short z_ = 32768; // does not compile (out of range)
test(a);
test(7); // does not compile (not applicable for arg int)
}
public static void test(short x) { }
Is the following summary correct (with regard to only the example above using short)?
direct initializations without casting is only possible using literals or single variables (as long as the value is in the range of the declared type)
if the rhs of an assignment deals with expressions using variables, casting is necessary
But why exactly do I need to cast the argument of the second method call taking into account the previous summary?
These are the relevant JLS sections:
JLS 5.1.1 Identity Conversion
A conversion from a type to that same type is permitted for any type.
JLS 5.2 Assignment Conversion
Assignment conversion occurs when the value of an expression is assigned to a variable: the type of the expression must be converted to the type of the variable. Assignment contexts allow the use of one of the following:
Identity conversion
[...]
In addition, if the expression is a constant expression 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.
The above rules explain all of the following:
short a = 4; // representable constant
short b = 5; // representable constant
short c = 5 + 4; // representable constant
short d = a; // identity conversion
short e = a + b; // DOES NOT COMPILE! Result of addition is int
short z = 32767; // representable constant
short z_ = 32768; // DOES NOT COMPILE! Unrepresentable constant
As to why this doesn't compile:
test(7); // DOES NOT COMPILE! There's no test(int) method!
It's because the narrowing conversion with constant is only defined for assignments; not for method invocation, which has entirely different rules.
JLS 5.3. Method Invocation Conversion
Method invocation conversions specifically do not include the implicit narrowing of integer constants which is part of assignment conversion. The designers of the Java programming language felt that including these implicit narrowing conversions would add additional complexity to the overloaded method matching resolution process.
Instead of explaining how method resolution works precisely, I will just quote Effective Java 2nd Edition, Item 41: Use overloading judiciously:
The rules that determine which overloading is selected are extremely complex. They take up thirty-three pages in the language specification, and few programmers understand all of their subtleties.
See also
Varying behavior for possible loss of precision
short x = 3; x += 4.6; compiles because of semantics of compound assignment
The result of an arithmetic operation on short values is always int. test(7) doesn't work, since you haven't said that 7 is of type short. The compiler should be a bit smarter here.
The '7' in the call test(7); is an int and will not be automatically converted to a short.
It works when you declare and initialize short values, but that's a special case for the compiler. This special case doesn't exist for method calls.

Categories