Print Friendly, PDF & Email

When we want a class to provide a set of operations on data of the same type in Java we use Java generics.

In other languages the same concept is called “templates”, but the idea is pretty much the same, restricts at compile time the data types that an object, method or property can accept to avoid inappropriate mixing of data types without losing flexibility.

When we have data of the same type we have better performance since the calculation of the memory address where the next piece of data is located is more simple.

Let’s say that we have a node object that will hold one and only one numeric value

package jaba.lists.linkedlists.singlelinkedlists.iterative;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Setter
@Getter
@EqualsAndHashCode(of = {"item"})
@ToString(of = "item")
public class Node {
    private int item;
    private Node next;

    public Node(int item) {
        this.item = item;
    }
}

Now let’s say that we want to link nodes with String inner type.

package jaba.lists.linkedlists.singlelinkedlists.iterative;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Setter
@Getter
@EqualsAndHashCode(of = {"item"})
@ToString(of = "item")
public class Node {
    private String item;
    private Node next;

    public Node(String item) {
        this.item = item;
    }
}

But in order to support them both in the same class we have two approaches, the old school one which is:

package jaba.lists.linkedlists.singlelinkedlists.iterative;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Setter
@Getter
@EqualsAndHashCode(of = {"item"})
@ToString(of = "item")
public class Node {
    private Object item;
    private Node next;

    public Node(Object item) {
        if(item instanceOf Integer.class || item instanceOf int.class || item instanceOf String.class)
        this.item = item;
    }
}

But that actually is proclive to bad practices since ( very common if you come from JavaScript side ), since it doesn’t guarantee that you can’t accidentally mix String and int objects.

Java Generics syntax

We can define Java generics at

  • Class level
  • Method level
  • Property level

At class level we can use this syntax:

public ClassName<DataType1,DataType2,DataType3,DataTypeN>{
}

At method level we can use this syntax:

public <DataType extends Something> void methodName(DataType target) {
}

And at field level we can use this syntax:

private Type myVariable;

However, for field-level generic declaration, you generally should also define your generic data type in the class section as a good practice.

Introducing Generics to our example

The other option is using generics as follows:

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

/**
 * Created by Javatlacati on 30/05/2017.
 * @param <Type> Type of contained objects
 * @author Javatlacati
 */
@Setter
@Getter
@EqualsAndHashCode(of = {"item"})
@ToString(of = "item")
public class Node<Type> {
    private Type item;
    private Node<Type> next;

    public Node(Type item) {
        this.item = item;
    }
}

Now we can specify the type for every instance having a subtype restriction at compile time.

Node<String> stringNode = new Node("hello");
Node<Integer> integerNode = new Node(new Integer(10));
Node<Integer> integerNode1 = new Node(5); //autowrapping

stringNode.setNext(new Node<String>("Hello"));
stringNode.getNext().setNext(new Node<>("World"));
stringNode.getNext().getNext().setNext(new Node<>(3)); //compiler complains

When we use generics the only restriction is that every primitive gets wrapped.