Inferência generalizada de tipo de destino em Java
1. Introdução
A Inferência de tipo foi introduzida no Java 5 para complementar a introdução de genéricos e foi substancialmente expandida nas seguintes versões do Java, também conhecida como Inferência de tipo de destino generalizada.
Neste tutorial, vamos explorar esse conceito com exemplos de código.
2. Genéricos
Os genéricos nos proporcionaram muitos benefícios, como maior segurança de tipo, evitando erros de conversão de tipo e algoritmos genéricos. Você pode ler mais sobre os genéricos nestearticle.
No entanto, a introdução degenerics resulted in the necessity of writing boilerplate code due to the need to pass type parameters. Alguns exemplos são:
Map> mapOfMaps = new HashMap>();
List strList = Collections.emptyList();
List intList = Collections.emptyList();
3. Inferência de tipo antes do Java 8
Para reduzir o detalhamento de código desnecessário devido, Type Inference foi introduzido em Java que is the process of automatically deducing unspecified data types of an expression based on the contextual information.
Agora, podemos invocar os mesmos tipos e métodos genéricos sem especificar os tipos de parâmetros. O compilador infere automaticamente os tipos de parâmetro quando necessário.
Podemos ver o mesmo código usando o novo conceito:
List strListInferred = Collections.emptyList();
List intListInferred = Collections.emptyList();
No exemplo acima, com base nos tipos de retorno esperadosList<String>eList<Integer>, o compilador é capaz de inferir o parâmetro de tipo para o seguinte método genérico:
public static final List emptyList()
Como podemos ver, o código resultante é conciso. Now, we can call generic methods as an ordinary method if the type parameter can be inferred.
No Java 5, poderíamos fazer Inferência de Tipo em contextos específicos, como mostrado acima.
O Java 7 expandiu os contextos em que poderia ser executado. Ele introduziu o operador diamante<>. Você pode ler mais sobre o operador diamante nestearticle.
Agora,we can perform this operation for generic class constructors in an assignment context. ; um exemplo é:
Map> mapOfMapsInferred = new HashMap<>();
Aqui, o compilador Java usa o tipo de atribuição esperado para inferir os parâmetros de tipo para o construtorHashMap.
4. Inferência generalizada de tipo de destino - Java 8
O Java 8 expandiu ainda mais o escopo da Inferência de Tipo. Nós nos referimos a esse recurso expandido de inferência como Inferência Generalizada de Tipo de Alvo. Você pode ler os detalhes técnicoshere.
O Java 8 também introduziu as expressões Lambda. Lambda Expressions do not have an explicit type. Their type is inferred by looking at the target type of the context or situation. O tipo de destino de uma expressão é o tipo de dados que o compilador Java espera, dependendo de onde a expressão aparece.
O Java 8 suporta inferência usando o Target-Type em um contexto de método. When we invoke a generic method without explicit type arguments, the compiler can look at the method invocation and corresponding method declarations to determine the type argument (or arguments) that make the invocation applicable.
Vamos analisar um exemplo de código:
static List add(List list, T a, T b) {
list.add(a);
list.add(b);
return list;
}
List strListGeneralized = add(new ArrayList<>(), "abc", "def");
List intListGeneralized = add(new ArrayList<>(), 1, 2);
List numListGeneralized = add(new ArrayList<>(), 1, 2.0);
No código,ArrayList<> não fornece o argumento de tipo explicitamente. Portanto, o compilador precisa inferir isso. Primeiro, o compilador examina os argumentos do método add. Em seguida, analisa os parâmetros passados em diferentes invocações.
It performs invocation applicability inference analysis to determine whether the method applies to these invocations. Se vários métodos forem aplicáveis devido à sobrecarga, o compilador escolheria o método mais específico.
Então,the compiler performs invocation type inference analysis to determine the type arguments.The expected target types are also used in this analysis. Ele deduz os argumentos nas três instâncias comoArrayList<String>,ArrayList<Integer>eArrayList<Number>.
A inferência de tipo de destino nos permite não especificar tipos para parâmetros de expressão lambda:
List intList = Arrays.asList(5, 2, 4, 2, 1);
Collections.sort(intList, (a, b) -> a.compareTo(b));
List strList = Arrays.asList("Red", "Blue", "Green");
Collections.sort(strList, (a, b) -> a.compareTo(b));
Aqui, os parâmetrosaeb não têm tipos explicitamente definidos. Seus tipos são inferidos comoInteger na primeira Expressão Lambda e comoString na segunda.
5. Conclusão
Neste artigo rápido, analisamos a Inferência de tipo, que, juntamente com os genéricos e a Lambda Expression, permite escrever código Java conciso.
Como de costume, o código-fonte completo pode ser encontradoover on Github.