Julian Rubin:
Por primeira linha principal não lança ClassCastException enquanto o segundo faz?
import java.util.function.Function;
class Scratch {
static <T> T getSomething(Function<Integer, T> fun) {
return (T) fun;
}
public static void main(String[] args) {
Scratch.<String>getSomething(x -> "hello");
String something = Scratch.<String>getSomething(x -> "hello");
}
}
Andy Turner:
A diferença é porque você não usar o resultado do método, no primeiro caso, mas você na segunda.
Um elenco é uma expressão , mas não é um StatementExpression
. Isso significa que você não pode escrever isso:
(String) somethingReturningAString();
mas você pode escrever:
String aString = (String) somethingReturningAString();
Em tempo de compilação, as inserções do compilador checkcast
instruções onde ele precisa, e onde ele pode:
- Não pode inserir um elenco para o primeiro caso, então nenhuma verificação ocorre.
- Ele pode (e deve) inserir um elenco no segundo caso, a fim de garantir que ele está atribuindo algo que é realmente uma
String
a umaString
variável. Como tal, ele verifica o elenco, e que falha.
É importante notar que existem alguns casos talvez inesperados, onde um elenco não é estritamente necessário, mas é inserido. Por exemplo:
Scratch.<String>getSomething(x -> "hello").toString();
falharia com um ClassCastException
, uma vez que seria transformado para:
((String) Scratch.getSomething(x -> "hello")).toString();
mesmo que Object
tem um toString()
método, e assim ele poderia invocar que, sem um elenco.