10 points on why we are still using primitive data types in java ? When to use primitive type and wrapper classes?


Before diving much deep into this topic i’ll recommend you to have knowledge of Autoboxing and unboxing in java - How it works internally in detail with 10 examples


When to use primitive data types?

1) Let's start with example where we will add two numbers using int and Integer-

For addition of two numbers we must prefer to use primitive data type, not the Object wrapper class.


If int has to added to int than compiler won’t do any boxing or unboxing. Example ->
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Autoboxing{
   public static void main(String[] args) {
          int i1 = 4;
          int i2 = 5;
          int i3 = i1 + i2;
   }
}
Java compiler will convert above code into -
//No conversions will be made by compiler

In above program we are adding int to int.
  • No boxing or unboxing is done.
  • No objects will be formed.
  • Performance will be very good.



But, let’s see what will happen when Integer has to added to Integer (first both will be converted to int) Example ->
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Autoboxing{
   public static void main(String[] args) {
          Integer i1 = 4;
          Integer i2 = 5;
          Integer i3 = i1 + i2;
   }
}

Java compiler will convert above code into -
public class Autoboxing{
   public static void main(String[] args) {
          Integer i1 = Integer.valueOf(4);
          Integer i2 = Integer.valueOf(5);
          Integer i3 = Integer.valueOf( i1.intValue() + i2.intValue() );
   }
}


In above program we are adding Integer to Integer.
  • First primitive int type 4 and 5 int will autoboxed to Integer i1 and i2 (two unnecessary Integer objects will be formed as compared to previous program where int and int were added, also for forming these objects two unnecessary autoboxing operations will be performed )
  • then, during addition both Integers will be unboxed to int (two unnecessary unboxing operations will be performed as compared to previous program),
  • then both ints are added and result is int
  • Ultimate result (i.e. int) is autoboxed to Integer object and will be referenced by i3 (one more unnecessary Integer object will be formed as compared to previous program, also for forming this objects one unnecessary autoboxing operation will be performed ).
Integer is an immutable class, so any change made to it will produce new object.

Conclusion - Just for performing addition of two numbers >
  • 3 unnecessary Integer objects were formed in heap.
    • For forming these 3 Integer objects 3 unnecessary autoboxing operations were performed.
    • two unnecessary unboxing operations were performed.

So, overall addition of two numbers using Integers turned out into very costly operation in terms of performance, boxing/unboxing and unnecessary object formations.
Just imagine a situation where 1000000’s... of number are being added using Integer, it will literally explode our heap memory and boxing/unboxing operations will have adverse effect on performance.


2) Object formation, memory constraint and garbage collection -
As explained in above example if possible use primitive types -
  • if you care about object formation in heap,
  • if you have memory constraint and
  • if you care about garbage collector’s performance.


3) Performance -
primitive types give better performance as compared to Objects because in that case no autoboxing/ unboxing is performed.(As explained in the above example)



4) Using primitive in applications -
We must use prefer to use primitive data types where lots of calculations have to performed. Example - Calculator application.



Let’s discuss one very important point -

5) int and Integer in for loop >
Let’s take one more example by demonstrating for loop where we must prefer to use primitive data type, not the Object wrapper class.

If int is used in for loop. Example ->

/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Autoboxing {
   public static void main(String[] args) {
          for (int i = 0; i < 2; i++) {
                 //code..
          }
   }
}
Java compiler will convert above code into -
//No conversions will be made by compiler

In above program we are using Integer in for loop >
  • No boxing or unboxing is done.
  • No objects will be formed.
  • Performance will be very good.




But, let’s see what will happen when Integer is used in for loop. Example ->
public class Autoboxing {
   public static void main(String[] args) {
          for (Integer i = 0; i < 2; i++) {
                 // code..
                 System.out.println("i= " + i);
          }
   }
}

Java compiler will convert above code into -
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class Autoboxing{
   public static void main(String[] args) {
          for (Integer i = Integer.valueOf(0);         //Declaration
                       i.intValue() < 2;                      //termination condition
                       i= Integer.valueOf(i.intValue()+1)  ){ //increment
                 // code..
                 System.out.println("i= " + i);
          }
   }
}


In above program we are using Integer in for loop >

In First loop,
    • initialization - declare and initialize Integer i = Integer.valueOf(0).  Only done once  (i.e. at start of for loop) (one unnecessary Integer object will be formed as compared to previous program where int was used in for loop, also for forming this object one unnecessary autoboxing operation will be performed )
    • termination_booleanVal -  i.intValue() < 2 (i.e. 0<2) evaluates to true. (one unnecessary unboxing operation will be performed)
Program will enter for loop, print i= 0
In second loop,
    • increment/Decrement - i= Integer.valueOf(i.intValue()+1)  is called, i becomes 1 (one unnecessary unboxing operation will be performed and then one unnecessary Integer object will be formed, also for forming this objects one unnecessary autoboxing operations will be performed )

    • termination_booleanVal -  i.intValue() < 2 (i.e. 1<2) evaluates to true. (one unnecessary unboxing operation will be performed)

Program will enter for loop, print i= 1
Then (Attempt for third loop),
    • increment/Decrement - i= Integer.valueOf(i.intValue()+1) is called, i becomes 2 (one unnecessary unboxing operation will be performed and then one unnecessary Integer object will be formed, also for forming this objects one unnecessary autoboxing operations will be performed )
    • termination_booleanVal -  i < 2 (i.e. 2<2) evaluates to false. (one unnecessary unboxing operation will be performed)

Program will not enter for loop, and exit for loop.

Conclusion - In executing simple for loop using Integer as compared to previous program where int was used in for loop >
  • 3 unnecessary Integer objects were formed in heap.
    • For forming these 3 Integer objects 3 unnecessary autoboxing operations were performed.
    • 5 unnecessary unboxing operations were performed.

So, overall executing simple for loop using Integer turned out into very costly operation in terms of performance, boxing/unboxing and unnecessary object formations.
Just imagine a situation where loop is executed till 100000000, it will literally explode our heap memory and boxing/unboxing operations will have adverse effect on performance (See next point for more).



6) Let’s compare performance when int and Integer are used in for loop >
When int is used in for loop -
import java.util.GregorianCalendar;
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class IntPerformanceInForLoop {
   public static void main(String[] args) {
          GregorianCalendar cal1 = new GregorianCalendar();                
         
          for (int i = 0; i < 2147483647; i++) {
                 // code..
          }
         
          GregorianCalendar cal2 = new GregorianCalendar();         
          long diffIn_MilliSec = Math.abs(cal1.getTimeInMillis() - cal2.getTimeInMillis());
          System.out.println("for loop with int completed in "+ diffIn_MilliSec+" milliSeconds");
   }
}
/*output
for loop with int completed in 3 milliSeconds
*/

When Integer is used in for loop -
import java.util.GregorianCalendar;
/** Copyright (c), AnkitMittal JavaMadeSoEasy.com */
public class IntegerPerformanceInForLoop {
   public static void main(String[] args) {
          GregorianCalendar cal1 = new GregorianCalendar();                
         
          for (Integer i = 0; i < 2147483647; i++) {
                 // code..
          }
         
          GregorianCalendar cal2 = new GregorianCalendar();         
          long diffIn_MilliSec = Math.abs(cal1.getTimeInMillis() - cal2.getTimeInMillis());
          System.out.println("for loop with Integer completed in "+diffIn_MilliSec+" milliSeconds");
   }
}
/*output
for loop with Integer completed in 4928 milliSeconds
*/

As we can see >
When int is used in for loop program completed in 3 milliSeconds
but, when Integer is used in for loop program completed in 4928 milliSeconds.
So, we can see that performance of for loop with Integer degraded significantly because of -
  • unnecessary Integer objects formation in heap
  • Frequent execution of garbage collection processes.
    • unnecessary autoboxing/ unboxing operations.

Note : Performance may vary upon different machines.





When to use Object wrapper class?

7) Initializing object wrapper class to null -
Using Objects can be handy at times because they can be initialized to null.
But primitive data types are always initialized to some default value. Example - int is initialized with 0, it can never be null.
Let’s take an example where initialization of int to 0 may be misleading. In an organization employee id or some other identification code being 0 may create numerous confusion to other developers.
Initializing Integer Object to null be very handy over there, it won’t be misleading neither it would create any confusion, because null means nothing. And also it can be used to throw NullPointerException which will be very handy for developer in handling error scenarios if something goes wrong.
8) Adding Object wrapper class in Collection -
Object wrapper class can be used when we are working with Collection, because primitive data types cannot be added in Collection Api’s.

Note : whenever you add primitive data type in Collection Api’s it is autoboxed to corresponding object wrapper class.


9) Loading Object wrapper class  at runtime  -
Object wrapper classes can be loaded at runtime using reflection. But primitive data type doesn’t provide this support, because reflection can only be used to load classes at runtime.


10) Lot’s of methods are provided by Object wrapper class
Object wrapper classes provides so many methods like valueOf(xxx) and xxxValue(), but primitive data type  int does not provide any such methods.

Example to see what methods does wrapper class Integer provides-
Convert Integer wrapper object to any primitive data type >
  • byteValue()
  • shortValue()
  • intValue()
  • longValue()
  • floatValue()
  • doubleValue()
Convert String into primitive data type >
  • parseInt(“String”)
Example > int i = parseInt(“3”);

Convert String into Integer wrapper object  and Convert primitive data type into Integer wrapper object >
Convert String into Integer wrapper object  >
  • valueOf(String s)
Example > Integer i = valueOf(“3”);
Convert primitive data type into Integer wrapper object >
  • Integer valueOf(int i)
Example > Integer i = valueOf(3);


RELATED LINKS>

Autoboxing and unboxing in java - How it works internally in detail with 10 examples- Widening, AutoBoxing and Var-args

Java caches Integer objects formed from primitive int values between values -128 to 127

Method overloading with Widening, Autoboxing and Var-args - Who beats whom in java?

Change boxing or Unboxing Setting in eclipse in java - Advantages


Collection in java

Collection - List, Set and Map all properties in tabular form

Creating Immutable class in java


No comments:

Post a Comment