Why use a generic return?

Asked

Viewed 994 times

18

I was looking at the signature of the class methods Optional and I don’t understand what that means <T> in front of the return of the method empty():

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

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

2 answers

16


Understanding the syntax

Considering the important part:

<T> Optional<T> empty()

T is a type variable. This works more or less like a variable in a template, where you can replace T by some guy, remembering that guy 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 hint to the compiler (and to the inattentive programmer).

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

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

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

Optional<String> empty()

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

It is worth remembering that the inference of generic types is a compilation-time guarantee that there will be no incompatibility between types during assignments and accesses. Therefore, this has no influence during the execution of the program.

Another example

This is not the only way for the compiler to subunderstand 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();
}

As in the first example, <T> says the method is generic, the return will be of the type T and the method receives a class of type Class<T>. Example of use:

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

How Java Infers 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 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 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 prior to the type of 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 holds true for 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 that there is a convention for type variable names.

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

Generic type is strictly necessary?

No. Java generics are just a security issue for the programmer.

You might as well do it:

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

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

  • "However, if only the method is generic, the statement must come before the method, as in the example." only static methods or instances of classes as well?

  • @Patrick If the generic variable does not belong to the class it should be declared in all cases.

12

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 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. Then the method needs to be called indicating which type 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 he will call the equivalent of:

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

Call alternative within an expression:

Optional.<Integer>empty();

I put in the Github for future reference.

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

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

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

  • I didn’t understand the <T> before. Could it be omitted? The return is a Optional<T>, if the signature were public static Optional<T> empty() would be the same thing?

  • It wouldn’t be. Java doesn’t accept this syntax.

  • 3

    Although this was an instance method, such a construction could be useful if it operated on arbitrary types other than one of the generic types of the class. By the way, very interesting this way of using, did not know, +1.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.