What are Generics in Java?
Tags: java, beginners, programming, devrel
Published: 2023-01-25 22:43:33


Hello, today I will talk about Generics in Java, this text is focused on beginners who seek to learn a little more about Java.

Generics is an undefined type that can assume any kind, it has been added to Java seeking to avoid excessive code or casting repetitions.

To make it clearer we will create a scenario in which we need to print an object, but we do not know what types will use our method.

I will create the animal **abstract** class and extend it from two **Dog** and **Cat** classes.

``` java
abstract class Animal {
    public abstract void search();
}

class Dog extends Animal {
    String dog;

    public Dog(String dog) {
        this.dog = dog;
    }

    @Override
    public void search() {
        System.out.println("find Dog");
    }

    // Method to string was omitted.
}

class Cat extends Animal {

    String cat;

    public Cat(String cat) {
        this.cat = cat;
    }

    @Override
    public void search() {
        System.out.println("find Cat");
    }

    // Method to string was omitted.
}

```

Now let's create a method to present the information of an object at the terminal, as a rule, we can define that every method that has one toString() can be presented by the so-called Print. We can see that in class Printer() we do not have the specific type to be passed on the builder, it can be any object, the method print will present the information and if it does not have the method toString() the object's memory address will be presented. This method is that in some cases we want to present some information on Debug we can invoke this method.

``` java
class Printer <T> {
    T toPrint;

    public Printer(T toPrint) {
        this.toPrint = toPrint;
    }

    public void print() {
        System.out.println(toPrint);
    }
}
```

##### Case 01:

``` java
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Dog");
        Cat cat = new Cat("Cat");

        Printer<Integer> printer = new Printer(dog);
        printer.print();
    }
}
```

Now let's create a method to print the lists.

``` java
public static void printAnimal(List<? extends Animal> animals) {
    animals.stream().forEach(a -> a.search());
}
```

In this method is defined the type of the list as whatever type extend of animals, an important information is that we can not add anything to the list because Java in compilation time does not know what is within the list, so we will have the error in compilation time and not execution.
 
In this method we will all have Animal extension, containing Cat and Dog, this guarantees us a defensive programming, ensuring that we will present only what we want and nothing beyond.

##### Case 02:

``` java
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Dog");
        Cat cat = new Cat("Cat");

        List<Dog> dogList = Arrays.asList(dog);
        List<Cat> catList = Arrays.asList(cat);
        List<Animal> animals = Arrays.asList(dog, cat);

        printAnimal(dogList);
        printAnimal(catList);
        printAnimal(animals);
    }
}

```

Now I will present the last case that aims to create a list of 2 objects of different types.

``` java

public static <T, V> List<Object> createList(T thing, V otherThing) {

    return Arrays.asList(thing, otherThing);
}
```

This method is possible to create a list of different types without worrying about what will be inserted, this is useful when we have a situation that we can receive information that is not expected, so we can guarantee that we will be able to receive the information and later treat it.

In this case we will only make the object print on the terminal, but the idea is to understand basicly to apply to something larger.

##### Case 03:
``` java

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("Dog");
        Cat cat = new Cat("Cat");

       createList(dog, cat).stream().forEach(e -> {
           System.out.println(e);
       });
    }
}
```

An important thing is to know that generics exist only in the time of compilation in this way it keeps back the retro compatibility with Java versions, another important point is to point out that the examples presented here are for didactic purposes.