1 Lambda precisa ter um tipo funcional
Lambdas não podem ser atribuídas a tipos que não são interfaces funcionais, como Object.
Exemplo que não compila:
Object o = () -> {
System.out.println("eu sou um runnable!");
};
new Thread(o).start(); // Erro
2 Lambda atribuída corretamente a uma interface funcional
Atribuindo explicitamente para Runnable:
Runnable r = () -> {
System.out.println("eu sou um runnable!");
};
new Thread(r).start(); // Correto
3 Lambda passada diretamente como argumento
Quando passamos diretamente no construtor, o compilador usa o contexto para inferir o tipo:
new Thread(() -> {
System.out.println("eu sou um runnable?");
}).start();
O construtor Thread(Runnable r) espera um Runnable, então o compilador infere que a lambda é Runnable.
4 Target Type
O tipo esperado pelo compilador baseado no contexto é chamado de Target Type.
O Target Type permite:
Inferir o tipo da expressão lambda;
Reconhecer que uma mesma lambda pode representar diferentes interfaces funcionais.
Exemplo com mesma expressão lambda e diferentes tipos:
Callable
PrivilegedAction
Na primeira linha: Callable.
Na segunda linha: PrivilegedAction.
O Target Type define o significado.
5 O mesmo acontece com Method Reference
A method reference também usa Target Type para inferência.
Exemplo com method reference
Callable
PrivilegedAction
A mesma referência callable::call pode se adaptar a diferentes interfaces.
6 Diferença entre Lambda e Method Reference
Method references tornam a inferência mais forte, porque o tipo está mais explícito.
Além disso, é permitida a conversão entre interfaces funcionais compatíveis.
Exemplo: ExemploTargetType.java