- Generic Types
- A Simple Box Class
- A Generic Version of the Box Class
- Type Parameter Naming Conventions
- Invoking and Instantiating a Generic Type
- The Diamond
- Multiple Type Parameters
- Parameterized Types
- Type Parameter Naming Conventions
- Example
- Output
- Tech Tutorials
- Tuesday, October 11, 2022
- Generics in Java
- Java Generics
- Generic class format in Java
- Java Generics - Type Parameter Naming Conventions
- Benefits of Generics in Java
Generic Types
A generic type is a generic class or interface that is parameterized over types. The following Box class will be modified to demonstrate the concept.
A Simple Box Class
Begin by examining a non-generic Box class that operates on objects of any type. It needs only to provide two methods: set, which adds an object to the box, and get, which retrieves it:
public class Box < private Object object; public void set(Object object) < this.object = object; >public Object get() < return object; >>
Since its methods accept or return an Object, you are free to pass in whatever you want, provided that it is not one of the primitive types. There is no way to verify, at compile time, how the class is used. One part of the code may place an Integer in the box and expect to get Integers out of it, while another part of the code may mistakenly pass in a String, resulting in a runtime error.
A Generic Version of the Box Class
A generic class is defined with the following format:
The type parameter section, delimited by angle brackets (<>), follows the class name. It specifies the type parameters (also called type variables) T1, T2, . and Tn.
To update the Box class to use generics, you create a generic type declaration by changing the code «public class Box» to «public class Box ". This introduces the type variable, T, that can be used anywhere inside the class.
With this change, the Box class becomes:
/** * Generic version of the Box class. * @param the type of the value being boxed */ public class Box < // T stands for "Type" private T t; public void set(T t) < this.t = t; >public T get() < return t; >>
As you can see, all occurrences of Object are replaced by T. A type variable can be any non-primitive type you specify: any class type, any interface type, any array type, or even another type variable.
This same technique can be applied to create generic interfaces.
Type Parameter Naming Conventions
By convention, type parameter names are single, uppercase letters. This stands in sharp contrast to the variable naming conventions that you already know about, and with good reason: Without this convention, it would be difficult to tell the difference between a type variable and an ordinary class or interface name.
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
You'll see these names used throughout the Java SE API and the rest of this lesson.
Invoking and Instantiating a Generic Type
To reference the generic Box class from within your code, you must perform a generic type invocation, which replaces T with some concrete value, such as Integer:
You can think of a generic type invocation as being similar to an ordinary method invocation, but instead of passing an argument to a method, you are passing a type argument — Integer in this case — to the Box class itself.
Type Parameter and Type Argument Terminology: Many developers use the terms "type parameter" and "type argument" interchangeably, but these terms are not the same. When coding, one provides type arguments in order to create a parameterized type. Therefore, the T in Foo is a type parameter and the String in Foo f is a type argument. This lesson observes this definition when using these terms.
Like any other variable declaration, this code does not actually create a new Box object. It simply declares that integerBox will hold a reference to a "Box of Integer", which is how Box is read.
An invocation of a generic type is generally known as a parameterized type.
To instantiate this class, use the new keyword, as usual, but place between the class name and the parenthesis:
The Diamond
In Java SE 7 and later, you can replace the type arguments required to invoke the constructor of a generic class with an empty set of type arguments (<>) as long as the compiler can determine, or infer, the type arguments from the context. This pair of angle brackets, <>, is informally called the diamond. For example, you can create an instance of Box with the following statement:
For more information on diamond notation and type inference, see Type Inference.
Multiple Type Parameters
As mentioned previously, a generic class can have multiple type parameters. For example, the generic OrderedPair class, which implements the generic Pair interface:
public interface Pair < public K getKey(); public V getValue(); >public class OrderedPair implements Pair < private K key; private V value; public OrderedPair(K key, V value) < this.key = key; this.value = value; >public K getKey() < return key; >public V getValue() < return value; >>
The following statements create two instantiations of the OrderedPair class:
Pair p1 = new OrderedPair("Even", 8); Pair p2 = new OrderedPair("hello", "world");
The code, new OrderedPair , instantiates K as a String and V as an Integer. Therefore, the parameter types of OrderedPair's constructor are String and Integer, respectively. Due to autoboxing, it is valid to pass a String and an int to the class.
As mentioned in The Diamond, because a Java compiler can infer the K and V types from the declaration OrderedPair , these statements can be shortened using diamond notation:
OrderedPair p1 = new OrderedPair<>("Even", 8); OrderedPair p2 = new OrderedPair<>("hello", "world");
To create a generic interface, follow the same conventions as for creating a generic class.
Parameterized Types
You can also substitute a type parameter (that is, K or V) with a parameterized type (that is, List ). For example, using the OrderedPair example:
OrderedPairBox > p = new OrderedPair<>("primes", new Box(. ));
Type Parameter Naming Conventions
By convention, type parameter names are named as single, uppercase letters so that a type parameter can be distinguished easily with an ordinary class or interface name. Following is the list of commonly used type parameter names −
- E − Element, and is mainly used by Java Collections framework.
- K − Key, and is mainly used to represent parameter type of key of a map.
- V − Value, and is mainly used to represent parameter type of value of a map.
- N − Number, and is mainly used to represent numbers.
- T − Type, and is mainly used to represent first generic type parameter.
- S − Type, and is mainly used to represent second generic type parameter.
- U − Type, and is mainly used to represent third generic type parameter.
- V − Type, and is mainly used to represent fourth generic type parameter.
Following example will showcase above mentioned concept.
Example
Create the following java program using any editor of your choice.
package com.tutorialspoint; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class GenericsTester < public static void main(String[] args) < Boxbox = new Box(); box.add(Integer.valueOf(10),"Hello World"); System.out.printf("Integer Value :%d\n", box.getFirst()); System.out.printf("String Value :%s\n", box.getSecond()); Pair pair = new Pair(); pair.addKeyValue("1", Integer.valueOf(10)); System.out.printf("(Pair)Integer Value :%d\n", pair.getValue("1")); CustomList list = new CustomList(); list.addItem(box); System.out.printf("(CustomList)Integer Value :%d\n", list.getItem(0).getFirst()); > > class Box < private T t; private S s; public void add(T t, S s) < this.t = t; this.s = s; >public T getFirst() < return t; >public S getSecond() < return s; >> class Pair < private Mapmap = new HashMap(); public void addKeyValue(K key, V value) < map.put(key, value); >public V getValue(K key) < return map.get(key); >> class CustomList < private Listlist = new ArrayList(); public void addItem(E value) < list.add(value); >public E getItem(int index) < return list.get(index); >>
This will produce the following result.
Output
Integer Value :10 String Value :Hello World (Pair)Integer Value :10 (CustomList)Integer Value :10
Tech Tutorials
Tutorials and posts about Java, Spring, Hadoop and many more. Java code examples and interview questions. Spring code examples.
Tuesday, October 11, 2022
Generics in Java
There have been many new feature additions in Java over the year, with introduction of lambda expressions in Java 8 it has even moved toward functional programming. But long before the lambda expressions and stream API there was one change which had a very big impact on the way you program and that was generics which was added in Java 5.
Generics in Java not only added a new way to declare classes, methods or interface but it also changed many of the classes in the API, Java collections API is an example. Initially it took some time getting used to the parameters like T, K or V with the classes or methods but now its quite a familiar thing and very much a part of your daily programming.
Java Generics
Generics in Java enable you to specify type parameters when defining classes, interfaces and methods. Here type parameter is the type of data (class or interface) which these classes, interfaces and methods will operate upon.
As example, when you say List that means a list which will store elements of type T. Since you have specified a type parameter so this List class is generic and T is the type parameter which specifies the type of element stored in the List.
Generic class format in Java
A generic class is defined using the following format:
The type parameter section, delimited by angle brackets (<>), follows the class name. It specifies the type parameters (also called type variables) T1, T2, . and Tn.
Java Generics - Type Parameter Naming Conventions
By convention, generic type parameter names are single, upper case letters. That helps n distinguishing between type parameters and normal variables.
- 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
Benefits of Generics in Java
You might be thinking there is already an Object class which provides almost the same thing, as Object is super class of all the other classes so Object class can be used to make a class generic. Though that can be done but it may cause some unseen problems because there is no type safety.
Let’s say you have a List where you intend to store strings and you have not made it generic that means all its elements will be stored as objects of type Object-
List strList = new ArrayList(); strList.add("a"); strList.add("b"); strList.add(new Integer(4)); Iterator itr = strList.iterator(); while(itr.hasNext())
Since elements are stored as class Object type so there won’t be any compile time error if you store an integer too (as done in this line strList.add(new Integer(4));), even if you intended to store Strings.
Since the elements are stored as class Object type so you need to cast those elements to String while retrieving. At that time you will get a run time exception when the code will try to cast Integer to String.
So the code snippet shown above will throw run time exception-
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
- Stronger type checks at compile time- In the above code if you use generics and specify the parameterized type of List as String you will get compile time error if an attempt is made to add element of any other type to the list. A Java compiler applies strong type checking to generic code and issues errors if the code violates type safety. Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find.
List strList = new ArrayList(); strList.add("a"); strList.add("b"); strList.add(new Integer(4));
List strList = new ArrayList(); strList.add("a"); strList.add("b"); strList.add("c"); Iterator itr = strList.iterator(); while(itr.hasNext())
Here you see casting is not required when retrieving elements from the list.
Let’s take a simple example to see how to create a generic class with parameterized type. While creating an object of the class you can specify the type, which in generics terminology is called generic type invocation, which replaces T with some concrete value.
public class GenType < T obj; public T getObj() < return obj; >public void setObj(T obj) < this.obj = obj; >>
public class GenericDemo < public static void main(String[] args) < // With Integer type GenTypegenInt = new GenType(); genInt.setObj(21); int value = genInt.getObj(); System.out.println("integer value " + value); // With String type GenType genStr = new GenType(); genStr.setObj("Generic class test"); String str = genStr.getObj(); System.out.println("String value " + str); // With Double type GenType genDouble = new GenType(); genDouble.setObj(34.56); double dblValue = genDouble.getObj(); System.out.println("Double value " + dblValue); > >
integer value 21 String value Generic class test Double value 34.56
- Generics in Java provide type safety as there are stronger type checks at compile-time.
- Generics don’t work with primitive types, type arguments passed to the type parameters must be references.
- You can have generic classes, generic methods and generic interfaces.
- Type parameters are erased when generic classes are compiled.
- A generic class with type parameters can’t have static members using the type parameter. As example -
That's all for this topic Generics in Java. If you have any doubt or any suggestions to make please drop a comment. Thanks!