I was reading effective java 2nd edition and page number 23 says
// Hideously slow program! Can you spot the object creation
public static void main(String[] args) {
Long sum = 0L;
for(long i=0; i<=Integer.MAX_VALUE; i++){
sum += i;
}
System.out.println(sum)
}
Author says that the above code generates 2^31 object instantiations unnecessarily. Why does sum += i generate new Object? if I change the statement to
sum = sum + 1
not have this side effect?
Generally when you work with collections, you're dealing with arrays of Objects. In languages like Java, there is a difference between a primitive and an Object. When a primitive is "boxed", it's essentially just a wrapper around a primitive so it plays nice with the rest of the framework that's expecting an Object.
In Java, when primitive values are boxed into a wrapper object, certain values (any boolean, any byte, any char from 0 to 127, and any short or int between -128 and 127) are interned, and any two boxing conversions of one of these values are guaranteed to result in the same object.
Objects are much more heavyweight than primitive types, so primitive types are much more efficient than instances of wrapper classes. Primitive types are very simple: for example an int is 32 bits and takes up exactly 32 bits in memory, and can be manipulated directly.
Verdict. Generally, choose primitive types over wrapper classes unless using a wrapper class is necessary. Primitive Types will never be slower than Wrapper Objects, however Wrapper Objects have the advantage of being able to be null.
Each of the primitive types in Java also has an equivalent reference type. For example, int has Integer, long has Long, boolean has Boolean, and so on. These reference types are called Boxed primitives. As it only supports values.
There are 8 primitive types: Reference types are references to objects. All reference types are a subclass of type java.lang.Object Following are 5 Java reference types. Each of the primitive types in Java also has an equivalent reference type. For example, int has Integer, long has Long, boolean has Boolean, and so on.
Primitive types are very simple: for example an int is 32 bits and takes up exactly 32 bits in memory, and can be manipulated directly. An Integer object is a complete object, which (like any object) has to be stored on the heap, and can only be accessed via a reference (pointer) to it.
Java boolean variables (the primitive ones) allow only two possible values: true or false, the last one as default. We use booleans to represent values that only can represent a true or a false statement, such as:
Trying to rephrase what others have said in a clearer way:
The problem with sum
is that Long is a reference type; in other words, it is some sort of Object. Objects live on the heap; they are created (using "new" and a constructor) by the JVM, and "managed" by the garbage collector.
The auto-boxing feature allows you to use that reference-type Long variable the same way you would use a primitive-type long variable.
But a Long object is immutable; once created, its value can never change. But the whole loop is about constantly changing a value (by incrementing the counter)! So, to increment the counter, you have to fetch the value of the "current" Long object; add 1; and stuff that into the next Long object. Again, and again, ...
So, what your program is doing here is: creating garbage all the time. In other words: those Long objects are created; used once (to retrieve their value); and then they are "forgotten" (because no reference to them is kept anywhere). So they are immediately eligible for garbage collection.
Meaning: there are actually two impacts on performance here:
Due to autoboxing as your variable sum
is not a primitive type but of type Long
(the wrapper class), sum += i
will behind the scene create a new Long
instance as it is an immutable class so it will somehow be equivalent to sum = new Long(sum.longValue() + 1)
sum = sum + 1
will still have same problem as sum += 1
because sum
on the right unboxes the value, then adds 1 to it, and finally creates a new Long
object in order to box the result and assign the sum
reference variable to point to the newly created object.
This happens because the java.lang.Long
class is immutable. In other words, a new Long
is created in each iteration of the loop instead of mutating the original in place. Compared to a primitive long
, the boxed Long
carries a lot of baggage. Your alternative statement, sum = sum + 1
would have the same effect as the original code. Redeclaring sum
as long sum = 0L;
would instead create a new long
on each iteration, which is substantially cheaper to create than a Long
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With