Generics Introduction

It would be nice if we could write a single sort method that could sort the elements in an Integer array, a String array or an array of any type that supports ordering (i.e., its elements can be compared). It would also be nice if we could write a single Stack class that could be used as a Stack of integers, a Stack of floating-point numbers, a Stack of Strings or a Stack of any other type. It would be even nicer if we could detect type mismatches at compile time—known as compile-time type safety. For example, if a Stack stores only integers, attempting to push a String on to that Stack should issue a compile-time error.

At its core, the term generics means parameterized types. Parameterized types are important because they enable you to create classes, interfaces, and methods in which the type of data upon which they operate is specified as a parameter. Using generics, it is possible to create a single class, for example, that automatically works with different types of data. A class, interface, or method that operates on a parameterized type is called generic, as in generic class or generic method.

Code that uses generics has many benefits over non-generic code:

Stronger type checks at compile time.
A Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find.

Consider the following example. In the example we have used two function to do the same task. One for Integer values and another for Double values.

public class OverloadedMethods 
{
   // method printArray to print Integer array
   public static void printArray( Integer[] inputArray )
   {
      // display array elements
      for ( Integer element : inputArray )
         System.out.printf( "%s ", element );

      System.out.println();
   } // end method printArray

   // method printArray to print Double array
   public static void printArray( Double[] inputArray )
   {
      // display array elements
      for ( Double element : inputArray )
         System.out.printf( "%s ", element );

      System.out.println();
   } // end method printArray

   public static void main( String args[] ) 
   {
      // create arrays of Integer, Double and Character
      Integer[] integerArray = { 1, 2, 3, 4, 5, 6 };
      Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };

      System.out.println( "Array integerArray contains:" );
      printArray( integerArray ); // pass an Integer array
      System.out.println( "\nArray doubleArray contains:" );
      printArray( doubleArray ); // pass a Double array
   }
} 

To overcome the above problem java uses generics. by using generics it’s possible to generate one function for similar task over the varying data types and reduce lines of code, as in the following example :

public class GenericMethodTest {
	// generic method printArray
	// <> are used for generic type specification and E is the argument of
	// generic type
	public static <E> void printArray(E[] inputArray) {
		// display array elements
		for (E element : inputArray)
			// E is used to carry actual work
			System.out.printf("%s ", element);

		System.out.println();
	} // end method printArray

	public static void main(String args[]) {
		// create arrays of Integer, Double and Character
		Integer[] integerArray = { 1, 2, 3, 4, 5, 6 };
		Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };

		System.out.println("Array integerArray contains:");
		printArray(integerArray); // pass an Integer array
		System.out.println("\nArray doubleArray contains:");
		printArray(doubleArray); // pass a Double array
	}
}