Diferenças entre final, final e finalização em Java
1. Visão geral
Neste tutorial, vamos dar uma visão geral de três palavras-chave Java:final, finally andfinalize.
Embora essas palavras-chave se assemelhem, cada uma tem um significado muito diferente em Java. Vamos aprender o propósito de cada um deles e ver alguns exemplos por meio de um pouco de código.
2. final palavra-chave
Vamos primeiro dar uma olhada na palavra-chavefinal, onde usá-la e por quê. We can apply the final keyword to class, method, field, variable and method parameter declarations.
It doesn’t have the same effect on each of them though:
-
Fazer uma classefinal significa que não será possível estender essa classe
-
Adicionarfinal a um método significa que não será possível substituir esse método
-
Finalmente, colocarfinal na frente de um campo, uma variável ou um parâmetro significa que uma vez que a referência foi atribuída, ela não pode ser alterada (no entanto, se a referência for para um objeto mutável, seu estado interno pode mudar apesar sendo final)
Um artigo detalhado sobre a palavra-chavefinal pode ser encontradohere.
Vamos ver como a palavra-chavefinal funciona por meio de alguns exemplos.
2.1. Campos, parâmetros e variáveis definal
Vamos criar uma classeParent com doisint fields, umfinal um e um não final regular:
public class Parent {
int field1 = 1;
final int field2 = 2;
Parent() {
field1 = 2; // OK
field2 = 3; // Compilation error
}
}
Como podemos ver, o compilador nos proíbe de atribuir um novo valor afield2.
Vamos agora adicionar um método com um argumento regular e um argumento final:
void method1(int arg1, final int arg2) {
arg1 = 2; // OK
arg2 = 3; // Compilation error
}
Da mesma forma que os campos, não é possível atribuir algo aarg2, pois é declarado final.
Agora podemos adicionar um segundo método para ilustrar como isso funciona com variáveis locais:
void method2() {
final int localVar = 2; // OK
localVar = 3; // Compilation error
}
Nada surpreendente acontece, o compilador não nos deixa atribuir um novo valor alocalVar após sua primeira atribuição.
2.2. Métodofinal
Agora, suponha que tornemosmethod2 final e criamos uma subclasse deParent, digamosChild, na qual tentamos sobrescrever seus métodos de superclasse:
public class Child extends Parent {
@Override
void method1(int arg1, int arg2) {
// OK
}
@Override
final void method2() {
// Compilation error
}
}
Como podemos ver, não há problema em substituirmethod1(), mas obtemos um erro de compilação ao tentar substituirmethod2().
2.3. Classefinal
E, finalmente, vamos tornar a classeChild final e tentar criar uma subclasse dela,GrandChild:
public final class Child extends Parent {
// ...
}
public class GrandChild extends Child {
// Compilation error
}
Mais uma vez, o compilador reclama. A classeChild é final e, portanto, impossível de estender.
3. Blocofinally
O blocofinally é um bloco opcional para usar com uma instruçãotry/catch. In this block, we include code to execute after the try/catch structure, whether an exception is thrown or not.
É ainda possível usá-lo com o blocotry sem nenhum blococatch, desde que incluamos um blocofinally. O código será então executado apóstry ou depois que uma exceção for lançada.
Temos um artigo detalhado sobre tratamento de exceções em Javahere.
Agora vamos demonstrar um blocofinally em um pequeno exemplo. Vamos criar um métodomain() fictício com uma estruturatry/catch/finally:
public static void main(String args[]) {
try {
System.out.println("Execute try block");
throw new Exception();
} catch (Exception e) {
System.out.println("Execute catch block");
} finally {
System.out.println("Execute finally block");
}
}
Se executarmos este código, ele produzirá o seguinte:
Execute try block
Execute catch block
Execute finally block
Vamos agora modificar o método removendo o bloco catch (e adicionarthrows Exception à assinatura):
public static void main(String args[]) throws Exception {
try {
System.out.println("Execute try block");
throw new Exception();
} finally {
System.out.println("Execute finally block");
}
}
A saída é agora:
Execute try block
Execute finally block
Se removermos agora a instruçãothrow new Exception(), podemos observar que a saída permanece a mesma. Nossa execução de blocofinally ocorre todas as vezes.
4. Métodofinalize
E, finalmente, o métodofinalize é um método protegido, definido emObject class. It’s called by the garbage collector on objects that aren’t referenced anymore and have been selected for garbage collection.
Como qualquer outro método não final, podemos sobrescrever este método para definir o comportamento que um objeto deve ter quando coletado porgarbage collector.
Novamente, um artigo detalhado cobrindo o métodofinalize pode ser encontradohere.
Vamos ver um exemplo de como funciona. UsaremosSystem.gc() para sugerir oJVM para acionargarbage collection:
@Override
protected void finalize() throws Throwable {
System.out.println("Execute finalize method");
super.finalize();
}
public static void main(String[] args) throws Exception {
FinalizeObject object = new FinalizeObject();
object = null;
System.gc();
Thread.sleep(1000);
}
Neste exemplo, substituímos o métodofinalize() em nosso objeto e criamos um métodomain() que instancia nosso objeto e imediatamente descarta a referência, definindo a variável criada paranull.
Depois disso, chamamosSystem.gc() para executar ogarbage collector (pelo menos esperamos que ele execute) e esperamos por um segundo (apenas para garantir que oJVM não desligue antes degarbage collector tem a chance de chamar o métodofinalize()).
A saída dessa execução de código deve ser:
Execute finalize method
Observe que é considerado uma má prática substituir o métodofinalize(), pois sua execução depende degarbage collection, que está nas mãos deJVM. Plus, this method has been deprecated since Java 9.
5. Conclusão
Neste artigo, discutimos brevemente as diferenças entre as três palavras-chave semelhantes em Java:final, finallyefinalize.
O código completo do artigo pode ser encontradoover on GitHub.