Java Generics – Get one step closer to become a Java Expert!

Suppose we have to make a list of human beings living in society. It doesn’t matter whether it’s a child, teen or adult. All that matters is they should be human. In such cases, we will not categorize them and will group them as a “Human Being”.

Similarly in Java when we store data we focus on the content and not datatype and that’s where Generics are used. Java Generics is a programming-language feature that allows for the definition and use of generic methods and generic types.

Today in this Java tutorial, we are going to study the Generics in Java and it’s Class with multiple parameters. We will also discuss various features and functions of generics in Java.

At last, we will learn how to use generics in Java to improve the quality of the code with the help of examples.

Java Generics Advantages

Java Generics

Java introduced the concept of Generics since Java 5 (J2SE 5) to deal with compile-time type checking and removing the risk of ClassCastException that was common while working with collection classes. Generics in Java is one of the most important features introduced since Java 5.

The term Generics in Java represents a set of features in a language, that relates to defining and using the generic methods and types. In Java, Generic methods and types are different from regular methods and types. They differ from each other as generic methods have type parameters.

We can see Java Generics as the templates in C++. Using Java Generics, we can use the wrapper classes like Integer, String, Double, etc and user-defined types as the parameters to classes, methods, and interfaces.

We can utilize the generics for any kind. For example, classes like HashSet, ArrayList, HashMap, etc use the Java Generics very well.

Need for Java Generics

Java Generics allow us to write a single method that could be able to perform operations in various types of objects that support that method.

Using Java Generic classes and methods, programmers can specify a set of related methods with a single/generic method declaration, or with a single class declaration.

For example, the Java Generics concept allows us to write a generic method for sorting an array of different types of objects, like to invoke the generic method with Character arrays, Integer arrays, String arrays, Double arrays and so on to sort the array elements.

Moreover, Java Generics provide compile-time type safety that allows the programmers to catch invalid types or faults during compilation.

Get to know more about Java Array in detail with Techvidvan.

Java Generic Classes

A generic class is a class that can refer to any type. To create a generic class of a specific type, we put the T type parameter. The angular brackets <> are used to specify parameter types in Java generic class creation.

Dive a little deep into the concept of Classes in Java to clear your basics.

Let’s discuss a simple example to create and use the generic class.

Creating a Generic Class

The declaration of a generic class is similar to a non-generic class declaration, the only difference is that the generic class name is followed by a type parameter section. The following code shows the creation of a generic class.

class MyGenClass<T>
{
       T obj;
       void add(T obj)
       {
              this.obj=obj;
       }
       T getObj()
       {
              return obj;
       }
}

Here, the type T indicates that it can refer to any type of class like Integer, String, Double, Character, and Employee, etc. The specified type of class will store and retrieve the data of the same type.

Note: In Parameter type, we cannot use primitives data types like ‘int’,’char’ or ‘double’, etc.

Using a Generic Class

class TestGenerics3
{
       public static void main(String args[])
       {
              MyGenClass<Integer> myObj = new MyGenClass<Integer>();
              myObj.add(18);
              //myObj.add("TechVidvan"); //Compile-time error
              System.out.println(myObj.getObj());
       }
}

Output:

18

Code to understand Generic Classes:

package com.techvidvan.javagenerics;
// We use < > to specify Parameter type
class MyGenericClass<T>
{
  // Declaring an object of type T
  T obj;
  // constructor
  MyGenericClass(T obj)
  {
    this.obj = obj;
  }
  public T getObject()
  {
    return this.obj;
  }
}
class GenericClassDemo
{
  public static void main (String[] args)
  {
    //Using Generic class for Integers
    MyGenericClass <Integer> intObj = new MyGenericClass<Integer>(15);
    System.out.println(intObj.getObject());

    //Using Generic class for String
    MyGenericClass<String> stringObj = new MyGenericClass<String>("TechVidvan");
    System.out.println(stringObj.getObject());
  }
}

Output:

15
TechVidvan

Using Multiple type Parameters in Generic Classes

We can also use multiple parameters of different types in a generic class, that is, the parameter type section of a generic class can have more than one type of parameter separated by commas.

These classes are known as parameterized classes since they accept more than one parameter.

Code to illustrate multiple type Parameters in Generic Classes:

package com.techvidvan.javagenerics;
class Test<T, U>
{
  T obj1; // An object of type T
  U obj2; // An object of type U
  // constructor
  Test(T obj1, U obj2)
  {
    this.obj1 = obj1;
    this.obj2 = obj2;
  }
  // To print objects of T and U
  public void getObject()
  {
    System.out.println(“String value: “ +obj1);
    System.out.println(“Integer value: ” +obj2);
  }
}
class Main
{
  public static void main (String[] args)
  {
    Test <String, Integer> obj = new Test<String, Integer>("TechVidvan", 15);
    obj.getObject();
  }
}

Output:

String value: TechVidvan
Integer value: 15

Type Parameters

The type parameter’s naming conventions are crucial for learning generics thoroughly. The common type parameters are as follows:

  1. T – Type
  2. E – Element
  3. K – Key
  4. N – Number
  5. V – Value

Java Generic Methods

We can declare a single generic method and we can call this method with arguments of different types. The compiler handles each method call appropriately according to the types of the arguments passed to the generic method.

Rules to define Generic Methods

  • There should be a type parameter section in all generic method declarations, delimited by angular brackets <> that precede the method’s return type.
  • If there is more than one parameter in the parameter list then each type parameter should be separated by commas.
  • We can also use the type parameters to declare the return type and let them act as placeholders for the types of arguments passed to the generic method, called as actual type arguments.
  • The method body of a generic method is declared similar to any other non-generic method.
  • The type parameter in a method can represent only reference types, non-primitive types like int, double and char.

Get familiar with the concept of Data types in Java in detail with Techvidvan.

Code to understand Generic Methods:

package com.techvidvan.javagenerics;
public class GenericMethodDemo
{
  // defining generic method printArray
  public static < E > void printArray( E[] inputArray )
  {
    // Displaying array elements
    for(E element : inputArray)
    {
      System.out.printf("%s ", element);
    }
    System.out.println();
  }

  public static void main(String args[])
  {
    // Create arrays of Integer, Double and Character
    Integer[] intArray = { 10, 20, 30, 40, 50 };
    Double[] doubleArray = { 1.2, 2.5, 4.6, 7.8 };
    Character[] charArray = { 'T', 'e', 'c', 'h', 'V', 'i', 'd', 'V', 'a', 'N' };

    System.out.println("Array integerArray contains:");
    printArray(intArray); // pass an Integer array

    System.out.println("\nArray doubleArray contains:");
    printArray(doubleArray); // pass a Double array

    System.out.println("\nArray characterArray contains:");
    printArray(charArray); // pass a Character array
  }
}

Output:

Array integerArray contains:
10 20 30 40 50
Array doubleArray contains:
1.2 2.5 4.6 7.8
Array characterArray contains:
T e c h V i d V a n

What is not allowed to do with Java Generics?

Now, we will discuss some tasks that are not allowed to do in Java Generics. So let’s examine each of them.

a) You can’t have a static field of type

In your generic class, you can not define a static generic parameterized member. Any attempt to do so will generate a compile-time error. The error will be like: Cannot make a static reference to the non-static type T.

public class GenericClass<T>
{
        private static T member; 	//This is not allowed
}

b) You can not create an instance of T

We can also not create an object of T. Any attempt to do so will fail with an error: Cannot instantiate the type T. For example,

public class GenericClass<T>
{
        public GenericClass()		//Constructor created
  {
    new T();	//Not Allowed
  }
}

c) We can’t use primitive data types with Generics declaration

We can’t declare generic expressions like List or Map <int, double>. But, we can use the wrapper classes in place of primitive data types and then use the primitives while passing the actual values. Auto-boxing converts these primitive types to their respective wrapper classes.

final HashMap<int> id = new HashMap<>();		//Not allowed

final HashMap<Integer> id = new HasMap<>();	//Allowed

d) You can’t create Generic exception class

We can’t pass an instance of generic type along with exception being thrown. This is not allowed in Java. For example, the following line causes an error.

// causes compiler error
public class GenericClass<T> extends Exception {}

When you try to do this, you will get an error message like this: The generic class GenericException may not subclass java.lang.Throwable.

Advantages of Java Generics

Applications that make use of Java Generics have several benefits over the non-generic code. Some of them are as follows –

1. Code Reuse

We can create a generic strategy or a class or an interface once and use it for any type we need and for any number of times.

For better understanding, you must explore the concept of Java Interface in detail.

2. Sort Safety

It is better to know the faults and issues in your code at compile-time rather than at run-time. Java Generics enables you to detect the faults at compile-time than at runtime.

Suppose, you need to make an ArrayList that stores the name of undergraduate students and if by mistake, software engineer includes an integer in place of a string, compiler permits it. However, when we try to gain this information from ArrayList, it causes issues at runtime.

class Test
{
  	     public static void main(String[] args)
  	     {
  	       	     // Creating an ArrayList with String specified
  	       	     ArrayList <String> al = new ArrayList<String> ();
  	       	     al.add("Sachin");
  	       	     al.add("Rahul");
  	       	     //Type Casting is required
  	       	     String s1 = (String)al.get(0);
  	       	     String s2 = (String)al.get(1);
  	       	     String s3 = (String)al.get(2);
  	     }
}

3. Individual Type Casting isn’t required

In the above case, if we don’t use Java generics, at that point, we need to typecast the ArrayList each time we recover information from it. It is a major headache to typecast at each recovery.

If we utilize the Java generics in our code, then we need not do typecasting at each recovery. The below code shows this concept:

class Test
{
 	     public static void main(String[] args)
 	     {
 	      	     // Creating an ArrayList with String specified
 	      	     ArrayList <String> al = new ArrayList<String> ();
 	      	     al.add("Sachin");
 	      	     al.add("Rahul");
 	      	     // Typecasting is not needed
 	      	     String s1 = al.get(0);
 	      	     String s2 = al.get(1);
 	     }
}

4. Implementing non-generic algorithms

We can perform the calculations that work on various sorts of items by utilizing generics in Java, and they are type-safe as well.

Summary

To use Java Generics for achieving type-safety, the whole collection framework was re-written. With this, we come to the end of our article on Java Generics.

In this article, we learned the basic concept of Java Generics along with its classes, methods, and uses. We also covered some advantages and need for Generics in Java with examples.

That was all about Java Generics. I hope this article helped you in understanding the concept of Java Generics.

Happy Learning 🙂