Key Points
- Java generics are a powerful tool that can make code more readable and reusable.
- Generics enable the creation of classes, interfaces, and methods that can operate on different data types while ensuring type safety.
- Using Java generics can improve code readability and performance, and they can be used for interfaces as well.
- Generics become increasingly important when creating larger projects in Java.
Java Generics is a powerful tool that can make your code much more readable and reusable. Its main function is to enable the creation of classes, interfaces, and methods that can operate on different data types while ensuring type safety.
In this today’s guide, we will go over what generics are and how they can be used to their fullest extent. Let’s jump in!
What Are Generics?
General Class Without Generics
If you wanted a class to work on multiple data types, you would normally have to make it operate on Object. Here’s what that might look like for a Stack class:
public class Stack {
private Object[] elements;
private int top;
public Stack(int capacity) {
elements = new Object[capacity];
top = -1;
}
public void push(Object item) {
if (top == elements.length - 1) {
throw new RuntimeException("Stack is full");
}
elements[++top] = item;
}
public Object pop() {
if (top == -1) {
throw new RuntimeException("Stack is empty");
}
return elements[top--];
}
public boolean isEmpty() {
return top == -1;
}
}
If we want to create a stack and put a number on it, we can simply do the following:
Stack stack = new Stack(5);
stack.push(10);
However, if we want to pop off a number and use it as an integer later, since it is technically an Object, we must cast it.
Object uncastedNumber = stack.pop();
int castedNumber = (int) uncastedNumber;
And then we can use it.
General Class with Generics
With Java Generics, this is unnecessary. Here’s how we can write the same class using it:
public class Stack<T> {
private T[] elements;
private int top;
@SuppressWarnings("unchecked")
public Stack(int capacity) {
elements = (T[]) new Object[capacity];
top = -1;
}
public void push(T item) {
if (top == elements.length - 1) {
throw new RuntimeException("Stack is full");
}
elements[++top] = item;
}
public T pop() {
if (top == -1) {
throw new RuntimeException("Stack is empty");
}
return elements[top--];
}
public boolean isEmpty() {
return top == -1;
}
}
Note that the @SuppressWarnings(“unchecked”) annotation is only there to keep Java from giving you the “unchecked cast” warning.
The use of angle brackets (<>) is a giveaway that generics are being used. As can be seen, <T> is placed after the class name, indicating that any class can be put there to tell Java what type of data is being operated on.
Then, anywhere in the function, the token T can be used to refer to the chosen class. Here’s can the generic class can now be used:
Stack<Integer> stack = new Stack<>(5);
stack.push(10);
int number = stack.pop();
Unlike the last example, casting is not necessary. It should be noted that the class that is put in angle brackets cannot be a primitive data type. Here, Integer is used instead of int, although they are often functionally equivalent.
Wrapping Up: Java Generics
Although you may not have realized it up until now, you have likely used generics before. They are often used with common classes like ArrayList, LinkedList, and HashMap. When these are used with generics, they are much more powerful, as they can easily be used on a wide variety of data.
Using Java generics will help you improve your code readability and performance. Although only a class example was shown, they can also be used for interfaces.
When creating larger projects in Java, generics become increasingly important, as your code becomes more flexible and adaptable. There is much more to learn, and we encourage you to learn everything you can about generics to become a more proficient developer!
The image featured at the top of this post is ©vchal/Shutterstock.com.