Estou surpreso que ninguém tenha realmente postado algum código real que seja descompilado para provar que há pelo menos alguma diferença menor.
Para a referência este foi testado contra a javacversão 8, 9e 10.
Suponha que este método:
public static int test() {
/* final */ Object left = new Object();
Object right = new Object();
return left.hashCode() + right.hashCode();
}
Compilar esse código como ele é, produz exatamente o mesmo código de byte de quando finalestaria presente ( final Object left = new Object();).
Mas este:
public static int test() {
/* final */ int left = 11;
int right = 12;
return left + right;
}
Produz:
0: bipush 11
2: istore_0
3: bipush 12
5: istore_1
6: iload_0
7: iload_1
8: iadd
9: ireturn
Deixar finalde estar presente produz:
0: bipush 12
2: istore_1
3: bipush 11
5: iload_1
6: iadd
7: ireturn
O código é praticamente auto-explicativo, caso exista uma constante de tempo de compilação, ele será carregado diretamente na pilha de operandos (não será armazenado na matriz de variáveis locais, como o exemplo anterior faz via bipush 12; istore_0; iload_0) - o que meio que faz sentido já que ninguém pode mudar isso.
Por outro lado, por que no segundo caso o compilador não produz istore_0 ... iload_0está além de mim, não é como se esse slot 0fosse usado de alguma forma (poderia encolher a matriz de variáveis dessa maneira, mas pode estar faltando alguns detalhes internos, não é possível diga com certeza)
Fiquei surpreso ao ver essa otimização, considerando o quanto os pequenos javacfazem. Como devemos sempre usarfinal ? Eu nem vou escrever um JMHteste (o que eu queria inicialmente), tenho certeza de que o diff está na ordem de ns(se possível, pode ser capturado). O único lugar em que isso pode ser um problema é quando um método não pode ser incorporado devido ao seu tamanho (e a declaração finalreduziria esse tamanho em alguns bytes).
Há mais dois finals que precisam ser abordados. Primeiro, quando um método é final(de uma JITperspectiva), esse método é monomórfico - e estes são os mais amados pelo JVM.
Depois, existem finalvariáveis de instância (que devem ser definidas em todos os construtores); estes são importantes, pois garantirão uma referência publicada corretamente, conforme tocado um pouco aqui e também especificado exatamente pelo JLS.