If the operations performed by several overloaded methods are identical for each argument type, they can be more conveniently coded using a generic method.
You can write a single generic method declaration that can be called with arguments of different types.
Based on the types of the arguments passed to the generic method, the compiler handles each method call appropriately.
The compiler ensures the type safety of your code, preventing many runtime errors.
Here is how we declare a generic method.
public static <T> T maximum(T value1, T value2)
A generic method declaration has a type-parameter section.
This section is identified by angle brackets that precede the method’s return type.
It contains one or more type parameters, separated by commas.
public static <T, S> T doSomething(T value1, S value2)
A type parameter is an identifier that specifies a generic type name.
int
, double
and char
).A type parameter can:
By convention, type parameter names are single, uppercase letters which is meant to contrast with variable naming conventions. Otherwise, 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:
How does the compiler know the type of T? It infers the type from how we invoke the method.
import java.util.*;
public class AddAndReturn {
public static <T> T addAndReturn(T element, List<T> list) {
list.add(element);
return element;
}
public static void main(String[] args) {
String stringElement = "stringElement";
List<String> stringList = new ArrayList<>();
String element = addAndReturn(stringElement, stringList);
Integer integerElement = Integer.valueOf(123);
List<Integer> integerList = new ArrayList<Integer>();
Integer element2 = addAndReturn(integerElement, integerList);
}
}
A generic method is implemented just like any other method.
The only difference is that you get to declare and use variables of the generic type (e.g. T
).
public static <T> void printArray(T[] inputArray) {
for (T element : inputArray)
System.out.printf("%s ", element);
System.out.println();
}
What is invoked when generic and non-generic methods are available?
public class AddAndReturn {
public static <T> void doSomething(T element) {
System.out.println("Called generic version.");
}
public static void doSomething(Number element) {
System.out.println("Called Number version.");
}
public static void doSomething(Integer element) {
System.out.println("Called Integer version.");
}
public static void main(String[] args) {
Integer element = Integer.valueOf(123);
doSomething(element);
}
}
Non-generic methods are given priority.
Erasure is the process in which the Java compiler removes the type-parameter section from a generic method and replaces the parameters' types with actual types.
By default all generic types are replaced with type Object
.
This:
public static <T> void doSomething(T element) {
T value = element;
// ...
}
becomes this:
public static void doSomething(Object element) {
Object value = element;
// ...
}
Write a generic method that
Write another generic method that
public static void main(String[] args) {
Integer i = null;
System.out.println(isItNull(i));
i = 123;
System.out.println(isItNull(i));
String s = null;
System.out.println(isItNull(s));
s = "Something";
System.out.println(isItNull(s));
Integer i2 = returnSame(i);
System.out.println(i2);
String s2 = returnSame(s);
System.out.println(s2);
}
You can find the solution to this exercise here.