Thursday, August 22, 2013

Why we need Wrapper classes in Java

The wrapper classes in the Java API serve two primary purposes : To provide a mechanism to "wrap" primitive values in an object so that the primitives can be included in activities reserved for objects and to provide an assortment of utility functions for primitives. In this post, we'll see what are wrapper classes, why we need them, how it differ from primitive data types and why we need them in Collection frameworks.
What is wrapper class
From the image, it's easily to get what is a wrapper and how it will going to relate wrapper classes in java.
In general, a wrapper class is any class which "wraps" or "encapsulates" the functionality of another class or component. These are useful by providing a level of abstraction from the implementation of the underlying class or component.
Each of Java's eight primitive data types has a class dedicated to it. These are known as wrapper classes, because they "wrap" the primitive data type into an object of that class. 
So, there is an Integer class that holds an int variable, there is a Double class that holds a double variable, and so on for byte, short, int, long, float, double, boolean, & char.

How wrapper class differ from primitive datatypes?

For instance,
int x = 25;
Integer y = new Integer(33);

The first statement declares an int variable named x and initializes it with the value 25. The second statement instantiates an Integer object. The object is initialized with the value 33 and a reference to the object is assigned to the object variable y. See the memory assignment in the following image.



Clearly x and y differ by more than their values: x is a variable that holds a value; y is an object variable that holds a reference to an object.

So data fields in objects are not, in general, directly accessible. So, the following statement using x and y as declared above is not allowed
int z = x + y; // wron

The data field in an Integer object is only accessible using the methods of the Integer class. One such method — the intValue() method — returns an int equal to the value of the object, effectively "unwrapping" the Integer object

int z = x + y.intValue(); // OK


How object (wrapper) have more overhead than their primitive counterparts?

We see this with the help of an example:
we first put a number of primitive values into an collection and an array. Then we do an arithmetic operation on each value of the collection or array. The array loop performs much better than the collection loop, since collections need to perform boxing conversions before doing arithmetic multiplication on their contents. 
import java.util.*;
public class AutoBoxingPerformanceTest{
    public static void main(String args[]){
        long time1 = 0;
        long time2 = 0;
        List listValues = new ArrayList();
        int arrValues[] = new int[1000000];
        /* Inserting values into List and Array */
        for(int i =0;i<1000000;i++){
            listValues.add(i);
            arrValues[i]=i;
        }
        /* Reterive the values from collection objects and do the multiplication*/
        time1 = System.currentTimeMillis();
        for(int i=0;i<1000000;i++){
            listValues.set(i,listValues.get(i)*10);
        }
        time2 = System.currentTimeMillis();
        System.out.println("AutoBoxing with Collection : "+(time2-time1)+"ms");
        /* Reterive the values from arrays and do the multiplication*/
        time1 = System.currentTimeMillis();
        for(int i=0;i<1000000;i++){
            arrValues[i]=arrValues[i]*10;
        }
        time2 = System.currentTimeMillis();
        System.out.println("Using an Array : "+(time2-time1)+"ms");
    }
}

Output :

AutoBoxing with Collection : 421ms
Using an Array : 0ms

So we have to be aware when we may be doing unnecessary things that could impact performance, such as autoboxing when we should not.


Why we need wrapper classes

  1. So that we can include wrapper classes in Collection.
  2. Null value is possible with wrapper classes.
  3. It can be handy to initalise Object with null or send null parameters to a method or constructor to indicate state or function. This can't be possible with primitives.
  4. We can treat wrapper classes generically / polymorphically as an object along with other objects.
  5. Sometime we initalise numbers to 0(default) or -1, depending on the scenario this may be incorrect or misleading to confusion.
  6. With wrapper we could get NullPointerException when something is being set incorrectly, which is more programmer friendly than some arbitrary bug down the line.
  7. *To get type safety we use generics and generics need objects not primitives.

What are disadvantage of Wrapper classes
As we have already seen the performance comparison of Wrapper over primitive counterparts.
  1. Primitive datatypes may be a lot faster than their corresponding wrapper types i,.e wrapper classes may perform slow.
  2. There can some unexpected behavior involving
    == comparing references
    .equal()  comparing values

To prove above 2nd point, please run the following code
public class AutoBoxingTest{
    public static void main(String args[]){
        Integer iVar1 = new Integer(10);
        Integer iVar2 = 10;
        System.out.println("Lessthan Check : " + (iVar1 <= iVar2));
        System.out.println("Greater than Check : " + (iVar1 >= iVar2));
        System.out.println("Equality Check : " + (iVar1 == iVar2));
    }
}

How to choose between wrapper and primitive datatypes

  • Generally, you should use primitive types unless you need an object for some reason (e.g. to put in a collection)
  • There are certain constructs such as Collections require objects, and that objects have more overhead than their primitive counterparts as we seen above in term of memory and autoboxing.
  • If you still need wrapper, consider a different approach  that doesn't require object if you want to maximize the numeric datatype performance.
  • We also must consider that autoboxing i.e wrapper class doesn't reduce object creation, but it reduce code complexity.

Another question come into picture that we can store primitive directly in Collection. How come?
For instance,
List<Integer> list = new ArrayList<>();
list.add(1);
int i = list.get(0);

Java Collection can only store object references i.e, Collection store their values via references to an object memory location in the heap. 

As local variable are stored on stack, while storing primitive in collection, collection get the reference for a primitive data with the help of autoboxing i.e,it take the value from stack and wrap it for storage on heap.

If you see the add() method definition of Array List, it's look like this add(E e)

Above code is automatically converted into the following
List.add(Integer.valueOf(7));

Conclusion :
It's not recommended to use wrapper for scientific calculation. For instance, the code
d =  a * b + c ; 

is using Integer classes for a,b,c,& d and generate code will be look like 
d.valueOf(a.intValue() * b.intValue() + c.intValue())
All these method have there own overhead over primitive datatypes.
So, it is recommended to use wrapper when need to store primitive in Collection

Even, If you have huge collection of wrapper class like Integer wrapping int, the overhead can imply longer execution time as stated above.

Java designers kept the two separate to keep things simple. You use the wrappers when you need types that fit in the object oriented world - like polymorphism, collections etc.
You use the primitives when you need efficiency.


If you know anyone who has started learning Java, why not help them out! Just share this post with them. Thanks for studying today!...

2 comments:

  1. In my work we always use Wrapper (except on loops or count), this post help me to understand when use Wrapper.

    Keep with the great work.

    ReplyDelete
  2. Nice work , everyone can easily understand th concept :)

    ReplyDelete