Generics In Java
Tags: java, computerscience, programming, beginners
Published: 2021-04-21 11:20:13

## What is the meaning of Generics?

One of the definitions from Java docs :
> Generics allow you to abstract over types. The most common examples are container types, such as those in the Collections hierarchy.


In English:

Abstract over type means to group together similar and generalize them.

For Example: what do we do if we need to save firstName, lastName and email of multiple people do we create n number of variables to store and retrieve them manually OR 
we create an Abstraction over it known as **Class**.

Great!, Now we know what abstract over type means, but I still don't get how is it beneficial to us???

In short: Generics provides us with compile time type-checking and saves the need of manual type-casting.

In depth: Let's find out

Let's take an example of how Collection's used to work before introduction of generics.

```
List numList = new ArrayList(); // 1
numList.add(new Integer(1)); // 2
Integer x = (Integer) numList.iterator().next(); // 3    
```

Line 1 and Line 2 are simple, we created an ArrayList and added an Integer.

On Line 3 we have something that looks painful and will probably make you a little irritated **Manual Type Conversion** 

Just imagine doing that every single time.

In the above case even though the developer knows that the data is Integer at compile time we still need to manually convert it to Integer.

This was the best case scenario where even though it looks bad it still works **what if**

```
List list = new ArrayList(); //1
list.add("abc"); //2
list.add(new Integer(5)); //3 

for(Object obj : list){
    Integer numbers=(Integer) obj; 
}
```

Line 1 we created an ArrayList
Line 2 we add a String to list
Line 3 we add an Integer to the list

Wait what!!
We first added a String and now an Integer to the same list

Okay what's next
we iterate over List and try to manually type cast it to Integer 

So, we added a String and an Integer, and now we are expecting both of them to be type-casted to an Integer 

You know what's coming

### ClassCastException :fireworks: :boom:

We all know someone who is capable of doing this :wink:

What were the problems we found till now:
1. We need an abstraction over these so that we don't need to manually convert it every time
2. We need a compile time check to save us from **ClassCastException**


This is what our savior Generics helps us with 

How? Let's find out
```
List<String> listOfString = new ArrayList<>(); //1
listOfString.add("Generics"); //2
listOfString.add("are"); //3
listOfString.add("Awesome"); //4

for(String str : listOfString){ //5
     //no type casting needed, avoids ClassCastException
}
```

Most of the lines in the above code looks just as before except the manual typecast is gone :relieved: .

There is also something new on line 1
`List<String> listOfString = new ArrayList<>();`

`<>` is used in generics to help us define the type of data we are going to store in the list.

That's it that all we need to do for adding a compile time type safety.

What if someone tries to add an Integer to the above list?

![](https://i.imgur.com/2ODmFsk.png)

If we try to add an Integer we get a compile time error.


So, can we use Generics only with Collections?

No, Collections is just one of the places where we can use Generics. Let's look at other places where we can use Generics.

Let's start small 

## Generic Interface

```
interface Print<T>{
  void display(T input);
}
```
We can create generic interfaces which can be implemented by Classes with their respective data-type

```
class PrintInteger implements Print<Integer>{

  @Override
  public void display(Integer input) {
    System.out.println("Printing an int "+input);
  }
}
```

We have implemented Print interface and specified the data-type as Integer.

## Generics Class and Generic methods

Let's take a situation where we want to store firstName, lastName and an id of an employee but the data-type of id can be an int or long or String.

Code without Generics

```
class EmployeeWithIntegerId {
private String firstName;
private String lastName;
private int id;
}

class EmployeeWithLongId {
private String firstName;
private String lastName;
private long id;
}

class EmployeeWithStringId {
private String firstName;
private String lastName;
private String id;
}
```

We can see that without using generics we have to create 3 different classes to cater the situation.

Now, let's use generics to get us out of this situation

Code with Generics

```
class Employee<T>{
  private String firstName;
  private String lastName;
  private T id;
}
```
**T** in the above code represents the data-type of our id which will be decided by us while creating the instance of the class.

Is **T** mandatory to use?

No, **T** is just the most commonly used one, but it is not mandatory. We can use any alphabet we like in place of **T**.

For people who are interested in the best practices in naming convention
```
The most commonly used type parameter names are:

E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types
```
courtesy of java docs


Now, when we use generics we only needed to create a single class where the only thing that needs to be decided was the type of our variable id.

Okay, but how will the getters, setters and constructor work ??

### Constructor

```
  public Employee(String firstName, String lastName, T id) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.id = id;
  }
```

The constructor will look the same as before. It is one of the best and easy to understand example of generic methods.

### Getters and Setters

```
  public T getId() {
    return id;
  }

  public void setId(T id) {
    this.id = id;
  }
```

Okay, so we have defined the class, so how can we use it??

```
Employee<String> employee= new Employee<>("yash","sugandh","1234"); 
```
In the above example we created an object of the class Employee and while creating it we used `<>` operator to define the data-type of **T** as String.


There is a restriction on data-type that we cannot use primitive data-types, so we cannot use int we have to Integer, Long instead of long and so on.

Now, we know about generics and how it helps us in Collections, Interface, Classes and methods.

But, there are still few questions left
1. What are wildcards in generics ?
2. What is the meaning of bounded and unbounded wildcard ?
3. How does Java ensure backward compatibility from code with generics to code without generics?

Let's cover all these topics in the next post.

Please let me know if there are any questions in the comments below.

See you in the funny papers :rocket: