Why use a generic return?

14

I was looking at the signature class methods Optional and I did not understand what this <T> means in front of the method return empty() :

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

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

    
asked by anonymous 26.11.2015 / 22:28

2 answers

10

Understanding syntax

Considering the important part:

<T> Optional<T> empty()

T is a type variable . This works more or less as 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) / p>

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

The return type of the Optional<T> method 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 time you are going to use the method. As @bigown said, when you call the method assigning the result to a certain type, Java can 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 such as Eclipse and IntelliJ will show the signature with the proper replacement of T during auto-completion whenever it is possible to infer type by the current context.

It is worth remembering that generic type inference is a compile-time assurance that there will be no type mismatch during assignments and accesses. Therefore, this has no effect during the execution of the program.

Another example

This is not the only way the compiler will understand 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();
}

Just as in the first example, <T> says that the method is generic, the return will be of type T and the method will receive a class of type Class<T> . Example usage:

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

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

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

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 method type

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 statement must come before the method. This applies to both static and instance methods.

Note that you can mix generic classes and methods and use different names for type variables:

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

However, consider a convention for type variable names .

I believe that the decision to require the generic type declaration was taken for code readability issues, as well as avoiding obscure syntax not to confuse a generic type T with a class T {} .

Is the generic type strictly necessary?

No. Generics in Java are just a security issue for the programmer.

You may well do this:

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

And we went back to the Java 1.4 era, where there were no generic ones, but in compensation casts and ClassCastException errors popped up everywhere.

    
27.11.2015 / 01:15
11

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

The point is that a static method has no way of knowing which type was selected for the class. After all, the method belongs to the class and not to the instance. And the class is not instantiated. So the method needs to be called indicating which type should be used on it. This first <T> is the syntax used to receive this type.

Then 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();

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 so, but the creators of the language wanted to explicitly differentiate the case, or know something that something is a problem and I do not know.

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

    
26.11.2015 / 22:49