3860

Until today, I thought that for example:

i += j;

Was just a shortcut for:

i = i + j;

But if we try this:

int i = 5;
long j = 8;

Then i = i + j; will not compile but i += j; will compile fine.

Does it mean that in fact i += j; is a shortcut for something like this i = (type of i) (i + j)?

17
  • 158
    I'm surprised Java allows this, being a stricter language than its predecessors. Errors in casting can lead to critical failure, as was the case with Ariane5 Flight 501 where a 64-bit float cast to a 16-bit integer resulted in the crash. Commented Jan 5, 2015 at 16:31
  • 141
    In a flight control system written in Java, this would be the least of your worries @SQLDiver Commented Nov 2, 2015 at 9:24
  • 10
    Actually i+=(long)j; even will compile fine. Commented Mar 18, 2016 at 7:45
  • 9
    The constant push by one set of developers for accuracy and another for ease of use is really interesting. We almost need two versions of the language, one that is amazingly precise and one that is easy to use. Pushing Java from both directions moves it towards being unsuitable for either group. Commented Sep 19, 2017 at 16:03
  • 10
    if it did require casting, where would you put it? i += (int) f; casts f before addition, so it's not equivalent. (int) i += f; casts the result after assignment, not equivalent either. there would be no place to put a cast that would signify that you want to cast the value after adding, but before assignment. Commented Oct 24, 2018 at 13:09

12 Answers 12

2564

As always with these questions, the JLS holds the answer. In this case §15.26.2 Compound Assignment Operators. An extract:

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.

An example cited from §15.26.2

[...] the following code is correct:

short x = 3;
x += 4.6;

and results in x having the value 7 because it is equivalent to:

short x = 3;
x = (short)(x + 4.6);

In other words, your assumption is correct.

Sign up to request clarification or add additional context in comments.

2 Comments

So i+=j compiles as I checked myself, but it would result in loss of precision right? If that's the case, why doesn't it allow it to happen in i=i+j also? Why bug us there?
@ronnieaka: I'm guessing that the language designers felt that in one case (i += j), it is safer to assume that the loss of precision is desired as opposed to the other case (i = i + j)
510

A good example of this casting is using *= or /=

byte b = 10;
b *= 5.7;
System.out.println(b); // prints 57

or

byte b = 100;
b /= 2.5;
System.out.println(b); // prints 40

or

char ch = '0';
ch *= 1.1;
System.out.println(ch); // prints '4'

or

char ch = 'A';
ch *= 1.5;
System.out.println(ch); // prints 'a'

4 Comments

@AkshatAgarwal ch is a char. 65 * 1.5 = 97.5 -> Got it?
Yeah, but I can just see some beginner coming here, reading this, and going away thinking that you can convert any character from upper case to lower case by multiplying it by 1.5.
@DavidWallace Any character as long as it is A ;)
@PeterLawrey & @DavidWallace I will reveal your secret- ch += 32 =D
270

Very good question. The Java Language specification confirms your suggestion.

For example, the following code is correct:

short x = 3;
x += 4.6;

and results in x having the value 7 because it is equivalent to:

short x = 3;
x = (short)(x + 4.6);

4 Comments

Or more fun: "int x=33333333; x+=1.0f;".
@supercat , what trickery is this? A widening conversion that is incorrectly rounded, followed by an addition that doesn't actually change the result, casting to int again to produce a result that is most unexpected for normal human minds.
@neXus: IMHO, the conversion rules should have treated double->float as widening, on the basis that values of type float identify real numbers less specifically than those of type double. If one views double as a complete postal address and float as a 5-digit postal code, it's possible to satisfy a request for a postal code given a complete address, but it's not possible to accurately specify a request for a complete address given just a postal code. Converting a street address to a postal code is a lossy operation, but...
...someone who needs a complete address wouldn't generally be asking for just a postal code. Conversion from float->double is equivalent to converting US postal code 90210 with "US Post Office, Beverly Hills CA 90210".
184

Yes,

basically when we write

i += l; 

the compiler converts this to

i = (int) (i + l);

I just checked the .class file code.

Really a good thing to know.

6 Comments

Can you tell me which classfile this is?
@hexafraction: what you mean by class file? if you asking about the class file i mentioned in my post than it's the complied version of your java class
Oh, you mentioned "the" class file code, which led me to believe a specific classfile was involved. I understand what you mean now.
@Bogdan That shouldn't be a problem with properly used fonts. A programmer which chooses whe wrong font for programming should clearly think about how to proceed...
@glglgl I disagree that one should rely on font to distinguish in those cases... but everybody has the freedom to choose what thinks is best.
|
95

you need to cast from long to int explicitly in case of i = i + l then it will compile and give correct output. like

i = i + (int)l;

or

i = (int)((long)i + l); // this is what happens in case of += , dont need (long) casting since upper casting is done implicitly.

but in case of += it just works fine because the operator implicitly does the type casting from type of right variable to type of left variable so need not cast explicitly.

1 Comment

In this case, the "implicit cast" could be lossy. In reality, as @LukasEder states in his answer, the cast to int is performed after the +. The compiler would (should?) throw a warning if it really did cast the long to int.
65

The problem here involves type casting.

When you add int and long,

  1. The int object is cast to long & both are added and you get a long object.
  2. But the long object cannot be implicitly cast to int. So, you have to do that explicitly.

But += is coded in such a way that it does type casting. i = (int) (i + m)

Comments

54

In Java type conversions are performed automatically when the type of the expression on the right hand side of an assignment operation can be safely promoted to the type of the variable on the left hand side of the assignment. Thus we can safely assign:

 byte -> short -> int -> long -> float -> double. 

The same will not work the other way round. For example we cannot automatically convert a long to an int because the first requires more storage than the second and consequently information may be lost. To force such a conversion we must carry out an explicit conversion.
Type - Conversion

5 Comments

Hey, but long is 2 times larger than float.
A float can't hold every possible int value, and a double can't hold every possible long value.
What do you mean by "safely converted" ? From latter part of the answer I can deduce that you meant automatic conversion ( implicit cast ) which is of course not true in case of float -> long. float pi = 3.14f; long b = pi; will result in compiler error.
You'd be better off differentiating floating point primitive types with integer primitive types. They're not the same thing.
Java has simplistic conversion rules that require the use of casts in many patterns where behavior without casts would otherwise match expectations, but doesn't require casts in many patterns that are usually erroneous. For example, a compiler will accept double d=33333333+1.0f; without complaint, even though the result 33333332.0 would likely not be what was intended (incidentally, the arithmetically-correct answer of 33333334.0f would be representable as either float or int).
47

Sometimes, such a question can be asked at an interview.

For example, when you write:

int a = 2;
long b = 3;
a = a + b;

there is no automatic typecasting. In C++ there will not be any error compiling the above code, but in Java you will get something like Incompatible type exception.

So to avoid it, you must write your code like this:

int a = 2;
long b = 3;
a += b;// No compilation error or any exception due to the auto typecasting

2 Comments

Thanks for the insight regarding the comparison of the op use in C++ to its use in Java. I always like seeing these bits of trivia and I do think they contribute something to the conversation that may often be left out.
However the question itself is interesting, asking this in an interview is stupid. It does not prove that the person can produce a good quality code - it just proves that he had enough patience to prepare for an Oracle certificate exam. And "avoiding" the incompatible types by using a dangerous auto-conversion and thus hiding the possible overflow error, probably even proves that the person is not able to produce probable a good quality code. Damn the Java authors for all these auto-conversions and auto-boxing and all!
28

The main difference is that with a = a + b, there is no typecasting going on, and so the compiler gets angry at you for not typecasting. But with a += b, what it's really doing is typecasting b to a type compatible with a. So if you do

    int a = 5;
    long b = 10;
    a += b;
    System.out.println(a);

What you're really doing is:

    int a = 5;
    long b = 10;
    a = a + (int) b;
    System.out.println(a);

1 Comment

Compound assignment operators perform a narrowing conversion of the result of the binary operation, not the right-hand operand. So in your example, 'a += b' is not equivalent to 'a = a + (int) b' but, as explained by other answers here, to 'a = (int)(a + b)'.
12

Subtle point here...

There is an implicit typecast for i+j when j is a double and i is an int. Java ALWAYS converts an integer into a double when there is an operation between them.

To clarify i+=j where i is an integer and j is a double can be described as

i = <int>(<double>i + j)

See: this description of implicit casting

You might want to typecast j to (int) in this case for clarity.

1 Comment

I think a more interesting case might be int someInt = 16777217; float someFloat = 0.0f; someInt += someFloat;. Adding zero to someInt shouldn't affect its value, but promoting someInt to float may change its value.
9

Java Language Specification defines E1 op= E2 to be equivalent to E1 = (T) ((E1) op (E2)) where T is a type of E1 and E1 is evaluated once.

That's a technical answer, but you may be wondering why that's a case. Well, let's consider the following program.

public class PlusEquals {
    public static void main(String[] args) {
        byte a = 1;
        byte b = 2;
        a = a + b;
        System.out.println(a);
    }
}

What does this program print?

Did you guess 3? Too bad, this program won't compile. Why? Well, it so happens that addition of bytes in Java is defined to return an int. This, I believe was because the Java Virtual Machine doesn't define byte operations to save on bytecodes (there is a limited number of those, after all), using integer operations instead is an implementation detail exposed in a language.

But if a = a + b doesn't work, that would mean a += b would never work for bytes if it E1 += E2 was defined to be E1 = E1 + E2. As the previous example shows, that would be indeed the case. As a hack to make += operator work for bytes and shorts, there is an implicit cast involved. It's not that great of a hack, but back during the Java 1.0 work, the focus was on getting the language released to begin with. Now, because of backwards compatibility, this hack introduced in Java 1.0 couldn't be removed.

Comments

0

The += operator in Java is a powerful shortcut that efficiently combines two steps into one. Instead of writing i = i + j, where you need to add i and j and then store the result back in i, you can simply write i += j. This approach not only accomplishes the same task, but it does so with greater efficiency.

What sets += apart is its ability to automatically handle type conversions when necessary. For example, if j is a long—which can represent larger numbers than an int—the += operator seamlessly converts j to int before performing the addition with i. You don't need to explicitly manage these conversions yourself.

This built-in conversion is a result of well-defined rules in the Java language Specification (JLS) that allow it to manage types effectively in these scenarios (This is neither a bug nor an accident, In coding Developer should know what they are coding). Consequently, while both methods achieve the same outcome, using += significantly reduces the risk of type mismatch errors that you might encounter with the more verbose approach.

Here are some examples of using the += operator with different types:

Example 1: byte + int

byte b = 10;
int i = 20;
b += i; // equivalent to b = (byte) (b + i);

In this case, the int value i is converted to a byte before being added to b.

Example 2: short + long

short s = 10;
long l = 20;
s += l; // equivalent to s = (short) (s + l);

In this case, the long value l is converted to a short before being added to s.

Example 3: char + int

char c = 'a';
int i = 1;
c += i; // equivalent to c = (char) (c + i);

In this case, the int value i is converted to a char before being added to c.

Example 4: float + double

float f = 10.5f;
double d = 20.7;
f += d; // equivalent to f = (float) (f + d);

In this case, the double value d is converted to a float before being added to f.

Note that in each of these examples, the += operator performs a narrowing primitive conversion, which may result in a loss of precision or a change in the value of the result.

26 Comments

are you sure "converts j to int before performing the addition with i" ? The JLS 15.26.2. Compound Assignment Operators states that the convertion is done after the operation: "the saved value of the left-hand variable and the value of the right-hand operand are used to perform the binary operation ... the result of the binary operation is converted to the type of the left-hand variable"...
... the generated byte code is: i will be first converted to long (i2l), then added with j as long (ladd), and then the result converted to int (l2i) before being stored back to i || not sure what is meant by "efficiently combines two steps into one" - generated bytecode of i += j is same as of i = (int) (i + j) (OK, source code is smaller, easier to read)
And if someone thinks the order does not matter, try int i = 33_333_333; i +=1.0f; (compared to int i = 33_333_333; i +=(int)1.0f;)
@user85421 To answer your question: is Conversion Done Before or After? For Simple Assignment (=): Conversion happens after evaluating both sides of the expression. In your example: First, (i + j) evaluates as a long. Then Java attempts to assign this long value directly into an int variable (i). Since there’s no implicit cast here and potential precision loss exists, compilation fails unless you explicitly cast it like so: ```i = (int)(i + j); // Explicit cast required`` Comment 1/2
For Compound Assignment (+=): Conversion happens before assigning back into the left-hand side variable. In your example: First (i + j) evaluates as a long. Then Java implicitly casts this result back into an int before assigning it back into variable i. This implicit casting makes sure that no compilation error occurs. Thus, for compound assignments like +=, conversion happens during or immediately after evaluating (E1 op E2) but before assigning it back. Comment 2/2
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.