Diamond and Declaring a Generic Method


Diamond

//Version ≥ Java SE 7

Java 7 introduced the Diamond1 to remove some boiler-plate around generic class instantiation. With Java 7+ you can write:

List<String> list = new LinkedList<>();

Where you had to write in previous versions, this:

List<String> list = new LinkedList<String>();

One limitation is for Anonymous Classes, where you still must provide the type parameter in the instantiation:

// This will compile:
Comparator<String> customCaseInsensitiveComparator = new Comparator<String>() {
    @Override
    public int compare(String str1, String str2) {
        return str1.compareToIgnoreCase(str2);
    }
};
 
// But this will not:
Comparator<String> anotherCaseInsensitiveComparator = new Comparator<>() {
    @Override
    public int compare(String firstString, String secondString) {
        return firstString.compareToIgnoreCase(secondString);
    }
};
//Version > Java SE 8

Although using the diamond with Anonymous Inner Classes is not supported in Java 7 and 8, it will be included as a new feature in Java 9.


Declaring a Generic Method

Methods can also have generic type parameters.

public class CustomExample {
    // The type parameter U is scoped to the method
    // and is independent of type parameters of other methods.
    public <U> List<U> createList(U u1, U u2) {
        List<U> result = new ArrayList<U>();
        result.add(u1);
        result.add(u2);
        return result;
    }
 
    public void execute() {
        List<String> stringList = createList("Alice", "Wonderland");
        List<Double> doubleList = createList(3.14, 2.718);
    }
}

Notice that we don't have to pass an actual type argument to a generic method. The compiler infers the type argument for us, based on the target type (e.g. the variable we assign the result to), or on the types of the actual arguments. It will generally infer the most specific type argument that will make the call type-correct.

Sometimes, albeit rarely, it can be necessary to override this type inference with explicit type arguments:

void performTask() {
    processStream(this.<String>generateList("John", "Doe").stream());
}
 
void processStream(Stream<String> stringStream) {
    // Implementation of stream processing...
}

It's necessary in this example because the compiler can't "look ahead" to see that Object is desired for T after calling stream() and it would otherwise infer String based on the makeList arguments. Note that the Java language doesn't support omitting the class or object on which the method is called (this in the above example) when type arguments are explicitly provided.


Requiring multiple upper bounds ("extends A & B")

You can require a generic type to extend multiple upper bounds.

Example: we want to sort a list of numbers but Number doesn't implement Comparable

public <T extends Number & Comparable<T>> void sortNumbers( List<T> n ) {
     Collections.sort( n );
}

In this example T must extend Number and implement Comparable<T> which should fit all "normal" built-in number implementations like Integer or BigDecimal but doesn't fit the more exotic ones like Striped64.

Since multiple inheritance is not allowed, you can use at most one class as a bound and it must be the first listed. For example, <T extends Comparable<T> & Number> is not allowed because Comparable is an interface, and not a class

Basic Programs