"

Java Generic Methods

Generic programming can be done at the method level or class level.

Let’s look at generic methods first. An example is the method Collections.sort(), which can sort collections of objects of any type. To see how to write generic methods, let’s start with a non-generic method for counting the number of times that a given string occurs in an array of strings:

/**
 * Returns the number of times that itemToCount occurs in list. Items in the
 * list are tested for equality using itemToCount.equals(), except in the
 * special case where itemToCount is null.
 */

public static int countOccurrences(String[] list, String itemToCount) {
        int count = 0;

        if (itemToCount == null) {
            for (String listItem: list)
                if (listItem == null)
                    count++;
        } else {
            if (itemToCount.equals(listItem))
                return count;
        }

We have some code that works for type String, and we can imagine writing almost identical code to work with other types of objects by writing several overloaded methods. But, by writing a generic method, we get to write a single method definition that will work for objects of any non-primitive type. We need to replace the specific type String in the definition of the method with the name of a type parameter, such as T. However, if that’s the only change we make, the compiler will think that “T” is the name of an actual type, and it will mark it as an undeclared identifier. We need some way of telling the compiler that “T” is a type parameter. For a generic method, the “<T>” goes just before the name of the return type of the method:

public static <T> int countOccurrences(T[] list, T itemToCount) {
    int count = 0;

    if (itemToCount == null) {
        for (T listItem: list)
            if (listItem == null)
                count++;
    } else {
        for (T listItem: list)
            if (itemToCount.equals(listItem))
                count++;
    }

    return count;
}

The “<T>” marks the method as being generic and specifies the name of the type parameter that will be used in the definition. Of course, the name of the type parameter doesn’t have to be “T”; it can be anything. (The “<T>” looks a little strange in that position, I know, but it had to go somewhere and that’s just where the designers of Java decided to put it.)

Given the generic method definition, we can apply it to objects of any type. If wordList is a variable of type String[] and word is a variable of type String, then

int ct = countOccurrences( wordList, word );

will count the number of times that word occurs in wordList. If palette is a variable of type Color[] and color is a variable of type Color, then

int ct = countOccurrences( palette, color);

will count the number of times that color occurs in palette. If numbers is a variable of type Integer[], then

int ct = countOccurrences(numbers, 17);

will count the number of times that 17 occurs in numbers. This last example uses autoboxing; the 17 is automatically converted to a value of type Integer. Note that, since generic programming in Java applies only to objects, we cannot use countOccurrences to count the number of occurrences of 17 in an array of type int[].

A generic method can have one or more type parameters, such as the “T” in countOccurrences. Note that when a generic method is used, as in the function call “countOccurrences(wordlist, word)”, there is no explicit mention of the type that is substituted for the type parameter. The compiler deduces the type from the types of the actual parameters in the method call. Since wordlist is of type String[], the compiler can tell that in “countOccurrences(wordlist, word)”, the type that replaces T is String. This contrasts with the use of generic classes, as in “ArrayList<String>”, where the type parameter is specified explicitly.

The countOccurrences method operates on an array. We could also write a similar method to count occurrences of an object in any collection:

public static <T> int countOccurrences(Collection collection, T itemToCount) {
    int count = 0;

    if (itemToCount == null) {
        for (T item: collection)
            if (item == null)
                count++;
    } else {
        for (T item: collection)
            if (itemToCount.equals(item))
                count++;
    }
    return count;
}

Since Collection<T> is itself a generic type, this method is very general. It can operate on an ArrayList of Integers, a TreeSet of Strings, a LinkedList of Buttons, ….

License

Icon for the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License

Computer Science II Copyright © by Various is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License, except where otherwise noted.