What is Autoboxing and Unboxing in Java – Example Tutorial and Corner cases
What is Autoboxing in Java
Autoboxing and unboxing is introduced in Java 1.5 to automatically convert primitive type into boxed primitive( Object or Wrapper class). autoboxing allows you to use primitive and object type interchangeably in Java on many places like assignment, method invocation etc. If you have been using Collections like HashMap or ArrayList before Java 1.5 then you are familiar with the issues like you can not directly put primitives into Collections, instead you first need to convert them into Object only then only you can put them into Collections. Wrapper class like Integer, Double and Booleanhelps for converting primitive to Object but that clutter the code. With the introduction of autoboxing and unboxing in Java this primitive to object conversion happens automatically by Java compiler which makes code more readable. But autoboxing and unboxing comes with certain caveats which needs to be understood before using them in production code and it becomes even more important because they are automatic and can create subtle bugs if you are not sure when autoboxing in Java code occurs and when unboxing happens. This is my fifth article on features introduced in Java 5 after my post on Java Enum, How Generics works in Java and varargs example. In this Java tutorial we will see: What is autoboxing and unboxing in Java ? When autoboxing and unboxing occurs in Java? and things to remember while dealing with primitives and objects in Java with code examples.
What is autoboxing and unboxing in Java
When Java automatically converts a primitive type like int into corresponding wrapper class object e.g.Integer than its called autoboxing because primitive is boxed into wrapper class while in opposite case is called unboxing, where an Integer object is converted into primitive int. All primitive types e.g. byte, short,char, int, long, float, double and boolean has corresponding wrapper class e.g. Byte, Short, Integer,Character etc and participate in autoboxing and unboxing. Since whole process happens automatically without writing any code for conversion its called autoboxing and auto unboxing.
Important point about Autoboxing and Unboxing in Java
1) Compiler uses valueOf() method to convert primitive to Object and uses intValue(), doubleValue() etc to get primitive value from Object.
2) During autoboxing boolean is converted to Boolean, byte to Byte, char converted to Character, float changes toFloat, int goes to Integer, long goes to Long and short converts to Short, while in unboxing opposite happens like Float to float.
When does autoboxing and unboxing occurs in Java
Autoboxing and unboxing can happen anywhere where an object is expected and primitive type is available for example In method invocation where an object argument is expected, if you pass primitive, Java automatically converts primitive into equal value Object. Classic use of autoboxing is adding primitive types into Collection like ArrayList in Java or creating instance of parameterized classes e.g. ThreadLocal which expect Type. here is some code example of auto boxing and unboxing in Java:
ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(1); //autoboxing - primitive to object
intList.add(2); //autoboxing
ThreadLocal<Integer> intLocal = new ThreadLocal<Integer>();
intLocal.set(4); //autoboxing
int number = intList.get(0); // unboxing
int local = intLocal.get(); // unboxing in Java
intList.add(1); //autoboxing - primitive to object
intList.add(2); //autoboxing
ThreadLocal<Integer> intLocal = new ThreadLocal<Integer>();
intLocal.set(4); //autoboxing
int number = intList.get(0); // unboxing
int local = intLocal.get(); // unboxing in Java
You can find all places by applying some common sense as well, just see if an object needed or a primitive type and what is available there but don’t confuse between widening and autoboxing, where former refers to promoting small type into bigger type wherever expected e.g. converting byte to int. I have shared couple of conversion tutorial in java like String to int conversion and Double to String conversion, if you like you also check those.
Autoboxing and Unboxing Example in Java
In last section we discussed What is autoboxing and unboxing in Java and when does they occur. In short Autoboxing mainly occur in two places one is during assignment and other is during method invocation, let’s see couple of example of autoboxing and unboxing in Java to understand it better :
Autoboxing and unboxing in assignment:
This is the most common example of autoboxing in Java, earlier the code was bloated with explicit conversion which is now taken care by compiler.
//before autoboxing
Integer iObject = Integer.valueOf(3);
Int iPrimitive = iObject.intValue()
//after java5
Integer iObject = 3; //autobxing - primitive to wrapper conversion
int iPrimitive = iObject; //unboxing - object to primitive conversion
int iPrimitive = iObject; //unboxing - object to primitive conversion
Autoboxing and unboxing in method invocation:
This is another place where autoboxing makes your life easy, it allow you to pass Object or primitive interchangeably in a method without explicit conversion:
public static Integer show(Integer iParam){
System.out.println("autoboxing example - method invocation i: " + iParam);
return iParam;
}
//autoboxing and unboxing in method invocation
show(3); //autoboxing
int result = show(3); //unboxing because return type of method is Integer
System.out.println("autoboxing example - method invocation i: " + iParam);
return iParam;
}
//autoboxing and unboxing in method invocation
show(3); //autoboxing
int result = show(3); //unboxing because return type of method is Integer
When we call show(Integer) method which accept Integer object with primitive int autoboxing will first convert primitive to object and then call show() method. On the second line unboxing happens because show() method returns Integerwhile returned value is stored in primitive int variable result.
Unnecessary Object creation due to Autoboxing in Java
One of the danger of autoboxing is throw away object which gets created if autoboxing occurs in a loop. Here is an example of how unnecessary object can slow down your application :
Integer sum = 0;
for(int i=1000; i<5000; i++){
sum+=i;
}
for(int i=1000; i<5000; i++){
sum+=i;
}
In this code sum+=i will expand as sum = sum + i and since + operator is not applicable to Integer object it will trigger unboxing of sum Integer object and then autoboxing of result which will be stored in sum which is Integer as shown below :
sum = sum.intValue() + i;
Integer sum = new Integer(result);
Integer sum = new Integer(result);
here since sum is Integer, it will create around 4000 unnecessary Intger object which are just throw away and if this happens on large scale has It potential to slow down system with frequent GC for arithmetic calculation always prefer primitive over boxed primitive and look for unintentional autoboxing in Java
Autoboxing and method overloading in Java
autoboxing has complicated method overloading in Java, prior to Java 1.5 value(int) and value(Integer) were completely different and there was no confusion which method will be called based upon type of argument e.g. if you pass int first method will be called and if you pass Integer second method will be called. with autoboxing and unboxing in place it's get trickier. classic example of this is ArrayList remove() method which is overloaded i.e. remove(index) andremove(Object), Since now ArrayList has two remove() method autoboxing will not occur and respective method will get called as shown in below example of overloading with autoboxing in Java.
public void test(int num){
System.out.println("method with primitive argument");
}
public void test(Integer num){
System.out.println("method with wrapper argument");
}
//calling overloaded method
AutoboxingTest autoTest = new AutoboxingTest();
int value = 3;
autoTest.test(value); //no autoboxing
Integer iValue = value;
autoTest.test(iValue); //no autoboxing
Output:
method with primitive argument
method with wrapper argument
System.out.println("method with primitive argument");
}
public void test(Integer num){
System.out.println("method with wrapper argument");
}
//calling overloaded method
AutoboxingTest autoTest = new AutoboxingTest();
int value = 3;
autoTest.test(value); //no autoboxing
Integer iValue = value;
autoTest.test(iValue); //no autoboxing
Output:
method with primitive argument
method with wrapper argument
Things to remember while using autoboxing in Java
So far we have seen What is autoboxing means in Java , What is unboxing in Java and when does it occur, But every powerful feature comes with some caveats and corner cases, here are few which is worth remembering while using auto-boxing in Java:
1) Comparing Objects with equality Operator
I agree that autoboxing of primitive to Object adds lot of convenience and reduce verbosity but there are few places where autoboxing is error prone e.g. equality operator "==". Since equality operator can be applied on both primitive andObjects it leads to confusion and can cause subtle issues. When you compare two object using "==" operator it compares object's identity and not value and also no auto boxing occur. By the way you its not best practice to use equality operator to compare Objects, use equals method instead. here is an example which makes it clear :
Integer one = new Integer(1);
Integer anotherOne = new Integer(1);
if(one == anotherOne){
System.out.println("both one are equal");
}else{
System.out.println("Both one are not equal");
}
Integer anotherOne = new Integer(1);
if(one == anotherOne){
System.out.println("both one are equal");
}else{
System.out.println("Both one are not equal");
}
It will print "Both one are not equal" because of no autoboxing. Things gets more confusing when "==" comparison is combined with other logical operators like > and < which does auto unboxing before comparison. This one is explained beautifully with an example of Comparator in Effective Java, if you haven't read then go get a copy.
One of my reader Mitchee says that its not clear, so I am updating this section with few more details, Mitchee, let me know if it make sense:
One of my reader Mitchee says that its not clear, so I am updating this section with few more details, Mitchee, let me know if it make sense:
public class AutoboxingTest {
public static void main(String args[]) {
// Example 1: == comparison pure primitive – no autoboxing
int i1 = 1;
int i2 = 1;
System.out.println("i1==i2 : " + (i1 == i2)); // true
// Example 2: equality operator mixing object and primitive
Integer num1 = 1; // autoboxing
int num2 = 1;
System.out.println("num1 == num2 : " + (num1 == num2)); // true
// Example 3: special case - arises due to autoboxing in Java
Integer obj1 = 1; // autoboxing will call Integer.valueOf()
Integer obj2 = 1; // same call to Integer.valueOf() will return same
// cached Object
System.out.println("obj1 == obj2 : " + (obj1 == obj2)); // true
// Example 4: equality operator - pure object comparison
Integer one = new Integer(1); // no autoboxing
Integer anotherOne = new Integer(1);
System.out.println("one == anotherOne : " + (one == anotherOne)); // false
}
}
Output:
i1==i2 : true
num1 == num2 : true
obj1 == obj2 : true
one == anotherOne : false
public static void main(String args[]) {
// Example 1: == comparison pure primitive – no autoboxing
int i1 = 1;
int i2 = 1;
System.out.println("i1==i2 : " + (i1 == i2)); // true
// Example 2: equality operator mixing object and primitive
Integer num1 = 1; // autoboxing
int num2 = 1;
System.out.println("num1 == num2 : " + (num1 == num2)); // true
// Example 3: special case - arises due to autoboxing in Java
Integer obj1 = 1; // autoboxing will call Integer.valueOf()
Integer obj2 = 1; // same call to Integer.valueOf() will return same
// cached Object
System.out.println("obj1 == obj2 : " + (obj1 == obj2)); // true
// Example 4: equality operator - pure object comparison
Integer one = new Integer(1); // no autoboxing
Integer anotherOne = new Integer(1);
System.out.println("one == anotherOne : " + (one == anotherOne)); // false
}
}
Output:
i1==i2 : true
num1 == num2 : true
obj1 == obj2 : true
one == anotherOne : false
In first example both argument of == operator is primitive int type so no autoboxing occurs and since 1==1 it prints true
While in second example during assignment to num1, autoboxing occurs which converts primitive 1 into Integer(1)and when we compare num1==num2 unboxing occurs and Integer(1) is converted back to 1 by callingInteger.intValue() method and since 1==1 result is true. In Third example which is a corner case in autoboxing, both Integer object are initialized automatically due to autoboxing and since Integer.valueOf() method is used to convert int to Integer and it caches object ranges from -128 to 127, it returns same object both time. In short obj1 and obj2 are pointing to same object and when we compare two object with == operator it returns true without any autoboxing. In last example object are explicitly initialized and compared using equality operator , this time == return false because both one and anotherOne reference variables are pointing to different object.
2) Mixing object and primitive in equality and relational operator
Another mistake to avoid while using autoboxing and unboxing in Java is mixing primitive and Object in equality or relational operator much like mixing static and non static synchronized method. if we compare one primitive with another object than unboxing of object is occur which could throw NullPointerException if object is null e.g.
private static Integer count;
//NullPointerException on unboxing
if( count <= 0){
System.out.println("Count is not started yet");
}
//NullPointerException on unboxing
if( count <= 0){
System.out.println("Count is not started yet");
}
3) Cached Objects
One more caveat or danger of autoboxing and unboxing is cached object, since valueOf() is used to create boxed primitive and it caches frequently used Object which may behave differently based upon there value as Java only cache integers from -128 to 128. I have discussed this problem in detail on post What is wrong while using "==" with auto boxing in Java.
4) Unnecessary objects and GC overhead
Last but not least is cost associate on autoboxing and unboxing. Since autoboxing creates unnecessary object and if that goes beyond a limit usually outside the range of cached value it can potentially slow your program by frequently causinggarbage collection.
In Summary autoboxing and unboxing in Java are great convenience but demands care and awareness while using them. autoboxing and unboxing has several legitimate use case but should not be used with equality operator specially mixing with primitive and object is dangerous. If you like to read books check out Effective Java and Java 5.0 Tiger: A Developer's Notebook , those has some more insightful tips on autoboxing and unboxing in Java.
Other Java tutorials from this blog
1 comment:
michael kors handbags
tiffany and co
kobe basketball shoes
ray ban sunglasses
michael kors outlet store
fitflops clearance
cheap rolex watches
fitflops outlet
adidas tubular UK
cheap nfl jerseys
yeezy boost 350
jordans for cheap
tiffany and co jewellery
cheap jordan shoes
nike huarache
adidas tubular
cheap oakleys
adidas nmd runner
michael kors handbags clearamce
coach outlet online
jordans for cheap
Post a Comment