Generic Methods in Java

Naveen AnamaneniUpdated · 4 min read

Sometimes only one method needs to be flexible about types, not a whole class. "Return the last element of a list" works the same for a list of names, a list of marks or a list of dates. A generic method declares its own type parameter, so it can be written once and called with any type, while still returning the exact type it was given, with no casts.

Writing a Generic Method

Utils.java▶ Try it
import java.util.Arrays;
import java.util.List;
 
public class Utils {
    static <T> T lastOrDefault(List<T> list, T fallback) {
        return list.isEmpty() ? fallback : list.get(list.size() - 1);
    }
 
    static <T> void swap(T[] items, int i, int j) {
        T temp = items[i];
        items[i] = items[j];
        items[j] = temp;
    }
 
    public static void main(String[] args) {
        List<String> names = List.of("Navika", "Srihitha", "Advitha");
        String name = lastOrDefault(names, "none");
        Integer mark = lastOrDefault(List.of(), 0);
        System.out.println(name + " " + mark);
 
        String[] order = {"Navika", "Srihitha", "Advitha"};
        swap(order, 0, 2);
        System.out.println(Arrays.toString(order));
    }
}
Output
Advitha 0
[Advitha, Srihitha, Navika]

How it works

  1. static <T> T lastOrDefault(List<T> list, T fallback): the <T> before the return type declares the method's own type parameter. Then T is used for the parameters and the return type.
  2. With a list of strings, the compiler infers T = String, so the result is a String: no cast.
  3. With an empty list and a fallback of 0, it infers T = Integer.
  4. swap works on any object array. T is only in the parameters; its return type is void.

Where the <T> Goes

KindDeclaration
Static generic methodpublic static <T> T first(List<T> list)
Instance generic methodpublic <T> List<T> wrap(T item)
Several type parametersstatic <K, V> Map<K, V> mapOf(K k, V v)
Generic method inside a generic classclass Box<T> { <R> Box<R> map(Function<T, R> f) }: R is the method's own, T is the class's

A generic method can live in a non-generic class, as in Utils above. That's how most utility methods in the JDK work, such as Collections.max, Arrays.asList and List.of.

Type Inference and Explicit Types

The compiler works out T from the arguments and, if needed, from where the result is assigned. Occasionally there's nothing to infer from, and you can state the type explicitly with a type witness: ClassName.<Type>method().

Witness.java▶ Try it
import java.util.Collections;
import java.util.List;
 
public class Witness {
    public static void main(String[] args) {
        List<String> empty = Collections.emptyList();
        System.out.println(empty.size());
        System.out.println(Collections.<String>emptyList().size());
    }
}
Output
0
0

In the first line, T = String is inferred from the variable's type. In the second, there's no variable, so <String> is written explicitly. You'll rarely need this.

Common Mistakes

Putting <T> after the return type. It goes before: static <T> T first(...), not static T <T> first(...).

Declaring <T> on a method in a generic class that already has T. The method's T hides the class's T, which is confusing; use another letter.

Calling type-specific methods on T. Add a bound if you need them (see "Bounded Type Parameters in Java").

Interview Corner

What is a generic method?

A generic method declares its own type parameters, written in angle brackets before the return type, such as static <T> T first(List<T> list). It can be in a generic or non-generic class, and the compiler infers the type arguments from the call's arguments or target type. It gives one method type safety for any type without making the whole class generic.

Practice

  1. Easy: Write static <T> boolean contains(T[] items, T target) that uses equals, and test it with a String[] and an Integer[].
  2. Harder: Write static <K, V> Map<V, K> invert(Map<K, V> map) that swaps keys and values, and invert a map of student names to roll numbers.

Quick check: Generic methods

4 questions
1Where is a generic method's type parameter declared?
2How does the compiler usually know what T is?
3Can a non-generic class have generic methods?
4What is Collections.<String>emptyList()?

Key Takeaways

Was this tutorial helpful?

Lesson 241 of 482