A generic (or generic type) is a class or interface that has an argument. Generics enable developers to catch runtime errors during compilation. The result of this is easier debugging. As an application grows and becomes more complex, it becomes much more difficult to identify where an error occurred. However, if the compiler catches the error early on, then programmers can find the error with a lot less effort. This programming tutorial demonstrates how to use generics to enforce stronger type checks and catch errors at compilation rather than at runtime.
Read: Top Java Frameworks
How to Declare a Generic Class or Interface
To declare a generic in Java, simply follow the class or interface name with the diamond operator <>. In between these angle brackets, developers can place any non-primitive data type, such as an array, class, or interface. The variables between the diamond <> operator are referred to as type parameters or type variables:
class GenericDemo{ // some code }
There are a number of standard type parameters that the Java API defines. By convention, all these are single uppercase. This property distinguishes them from ordinary variables (which are lowercase by convention).
Below is a list of some of the standard type variables and their corresponding argument interpretation:
- T – Type
- K – Key
- V – Value
- N – Number
- E – Element
You can instantiate a generic class in a similar manner to instantiating a normal class. The only difference is that programmers need to include the <> operator after the class name; they must also place a specific type between them. Here is an example of how to instantiate a generic class in Java:
GenericDemo GenericObj = new GenericDemo();
You can leave out the second type declaration on the right hand side, as the compiler is able to deduce the exact type value. For the previously shown statement, that would be:
GenericDemo GenericObj = new GenericDemo<>();
Here is a Java code example that uses a generic class:
class GenericDemo { int getIntValue(T NumVal){ String val = NumVal.toString(); int a = Integer.parseInt(val); return a; } public static void main(String[] args) { Integer Val = 3; // Double Val = 1.1; GenericDemo GenObj = new GenericDemo<>(); System.out.println(GenObj.getIntValue(Val)); } }
The above code prints the value 3 on your command line. To understand why generics are important, let’s see an implementation of the same code, but this time without using a generic type:
class NoGeneric { int getIntValue(Object NumVal){ String val = NumVal.toString(); int a = Integer.parseInt(val); return a; } public static void main(String[] args) { NoGeneric NoGenObj = new NoGeneric(); Integer Val = 3; // Double Val = 1.1; System.out.println(NoGenObj.getIntValue(Val)); } }
In the first code example (GenericDemo), if you used the variable assignment Double Val = 1.1; instead of Integer Val = 3; , the compiler would toss an error, complete with details of where the error is located.
However, if you did the same substitution in the second code example (NoGeneric), your code would compile properly without giving off any warning errors. You would only get an error when running the compiled code (with no details of what went wrong where).
In the first example, the compiler checks that the type used is the one you indicated – namely, Integer. However, in the second example, it is not able to be strict about the type used.
For any non-trivial project, your code is bound to get bigger and possibly more complex. Being able to pinpoint exactly where the problem occurs can save a lot of time in the debugging process, hence the need for generic types in Java.
Generic types are not only useful to ensure stronger types checks. As mentioned earlier, parameter types are variables. Therefore, they can be used to represent various reference types. For example, the type variable N means the following types are acceptable: Integer, Float, and Double.
It is possible for developers to also use parameterized types as type variables. For example:
Name<K, Height name = new Name<>();
You can learn more about Java classes in our tutorial: Classes and Objects in Java.
Raw Types in Java
It is also possible for programmers to create an instance of a generic type without including a parameter. If you do so, the class or interface you create will be a raw type.
Here is an example of how to create a raw type in Java; we will call the class GenericDemo:
class GenericDemo <K, V> { // some code here }
To create a raw type of GenericDemo, use the following code example:
GenericDemo rawGeneric = new GenericDemo();
Before the release of JDK 5.0, there were no generic types. Because of this, raw types are used a lot in legacy code. Therefore, you can assign a parameterized generic to a raw type for compatibility with older code versions. However, you can not assign a raw type to a parameterized generic because the compiler is unable to deduce the type that is used. Here is an example of this concept:
Height height = new Height(); Height rawHeight = height; // accepted Height rawH = new Height(); Height heightVal = rawH ; // not allowed
Java Generic Methods
Just as with regular variables, developers can use type variables as parameters for methods, including constructors. You can also use them as return types. The basic code example below shows how to use generic methods in Java and demonstrates this concept:
public class AccountGeneric { N num; public AccountGeneric(N num) { this.num = num; } public N getNumber() { return num; } public static void main(String[] args) { AccountGeneric acct = new AccountGeneric(25014212); System.out.println(acct.getNumber()); } }
Final Thoughts on Java Generics
In this programming tutorial we discussed how to use generics in Java applications, We learned how to declare and instantiate generics, reviewed some examples of raw types, and had a brief note about generic methods. In general, generic types enable programmers to catch type inconsistencies at compile-time, reducing the time it takes to debug code and find errors in the applications we create.
We have a great tutorial discussing Interfaces in Java if you want to learn more about the concept.