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.