Why use a generic return?

Was looking at the signature of the class methods Optional and I didn't understand what this <T> means in front of the method returnempty():

public static <T> Optional<T> empty()

It returns a Optional<T>, right!?
But why use a <T> in front of the method return?

Author: Maniero, 2015-11-26

2 answers

Understanding the syntax

Considering the important part:

<T> Optional<T> empty()

T it is a variable of Type. This works more or less like a variable in a template, where you can replace T with any type, remembering that type in Java is synonymous with class (not to be confused with *primitive types).

The first <T> says: this method will use a generic type T somewhere. It's like a tip to the compiler (and for the inattentive programmer).

The return type of the method Optional<T> then says that the generic type of Optional must be of the same generic type as the method.

Confused, right? When will Java know the type T? This occurs at the moment when you are going to use the method. As @Maniero has already said, when you call the method assigning the result to a certain type, Java manages to infer the type used in that call.

For example, if you are assigning the method return to a variable of type Optional<String>, then T = String and you can read the method as:

Optional<String> empty()

In fact, more advanced IDEs like Eclipse and IntelliJ will show the signature with proper substitution of T during autocomplete whenever it is possible to infer type by the current context.

It is good to remember that generic type inference is a compile-time guarantee that there will be no mismatch between types during assignments and accesses. So this nothing influences during program execution.

Another example

This is not the only way the compiler understands the generic type. A classic example is a method that returns the same type passed by parameter:

static <T> T instanciar(Class<T> classe) throws IllegalAccessException, InstantiationException {
    return classe.newInstance();
}

In the same way as in the first example, <T> says that the method is generic, the return will be of type T and the method receives a class of type Class<T>. Usage example:

Cliente c = instanciar(Cliente.class);
Produto p = instanciar(Produto.class);

How does Java infer the type T here? The compiler looks at the class type passed in the parameter and thus ensures that the returned value is of the same type.

Different from the case of the question, where the type is inferred by the variable that receives the return of the method, here the type is inferred by one of the given parameters.

For example, Cliente.class is an attribute that returns an object of type Class<Cliente>, so the return of the first call will be to Type Cliente, where T = Cliente.

Because <T> is required before the method

There are generic classes/interfaces and generic methods. If the class / interface is generic, its methods can use the generic type.

Example:

interface Generico<T> {
    T empty();
}

Or:

class Generico<T> {
    T empty() { ... }
}

However, if only the method is generic, the declaration needs to come before the method. This applies to static and Instance Methods.

Note that you can mix generic classes and methods and use different names for the variables of types:

class Generico<T> {
    T empty() { ... }
    static <X> Optional<X> empty() { ... }
    <Y> Optional<Y> of(Y instance) { ... }
}

However, consider that there is a convention for variable names of types .

I believe that the decision to require the declaration of the generic type was made for reasons of code readability, as well as avoiding obscure syntaxes so as not to confuse a generic type T with a class T {}.

Is the generic type strictly necessary?

No. Generics in Java are just a matter of security for the developer.

You may well do this:

public static Optional empty() {
    return Optional.empty();
}

And we went back to the era of Java 1.4, where there were no generics, but in compensation casts and errors of ClassCastException appeared everywhere.

 16
Author: utluiz, 2019-09-16 17:15:02

This is a placeholder for the type that will be used. It's like a super variable. Its "value" is the type that was chosen from using the method or class. By then you probably know.

The issue is that a static method has no way of knowing what type has been selected for the class. After all the method belongs to the class and not to the instance and the class is not instantiated. Then the method needs to be called indicating what kind should be used in it. This first <T> is the syntax used to receive this type.

So you can use:

Optional<Integer> x = Optional.empty();

In this case it will call the equivalent of:

public static <Integer> Optional<Integer> empty() ...

Call alternative within an expression:

Optional.<Integer>empty();

I put on GitHub for future reference .

If the method had a parameter equal to the return it could infer by it but in this case the only way is to be explicit.

If you ask me if I could have a syntax without this I think but the creators of the language wanted to explicitly differentiate the case, or know of some problem that I do not know.

Always remember that the methods of the class are completely distinct from the methods of the instance and therefore the type of one may be different from the type of the other

 12
Author: Maniero, 2019-10-30 13:42:33