Java: Significado de catch (final SomeException e)?

O que o final faz na seguinte expressão Java?

 catch (final SomeExceptionType e) 

Basicamente significa:

Pegue “SomeExceptionType” na variável “e” com a promise de não atribuir uma exceção diferente a “e” durante o processamento da exceção.

Principalmente isso é um exagero, como se eu estivesse pegando uma exceção em um nome de variável temporária (e só é válido para o bloco de exception handling), eu não tenho que me policiar tão estritamente para não confiar em mim mesmo para atribuir um diferente ( possivelmente criado) exceção ao mesmo nome de variável.

Dito isto, talvez este bloco seja fortemente mantido por uma equipe de indivíduos de mente diferente, e um só queria ter certeza de que era a exceção original capturada.

—- Editado em resposta ao comentário —-

Não consigo pensar em uma razão realmente excelente para fazer isso. Como “e” não é um membro (estático ou não), o nome “e” não será usado pela pós-compilation do arquivo de class. Outra maneira de afirmar isso é que quando você insere o bloco de exception handling de bytecode da JVM, o object não será atribuído a nenhum dos nomes de membros acessíveis pelo quadro de processamento da JVM, ele será enviado para a pilha de processamento interno do Thread quadro atual.

Mesmo que duas threads tivessem access ao mesmo Object, cada thread teria seu próprio frame, então o nome “e” do compilador removido da pilha interna de um frame não poderia ser alterado pelo outro thread.

Com isso em mente, o único benefício de declarar “e” final é garantir que os codificadores futuros não configurem acidentalmente “e” depois de entrarem no bloco. Talvez eles significassem tornar o código mais robusto em um ambiente multi-threaded, mas variables ​​temporárias (aquelas com nomes que só são válidos no bloco) não possuem nomes pós-compilation, elas são colocadas na pilha do frame.

É por isso

 public int safe() { int x = 5; x = x + 5; return x; } 

é geralmente considerado como thread seguro, porque ele faz isso (em pseudo bytecode)

 (In the thread's current frame) push 5 push 5 add integers return 

Enquanto isso não é thread-safe

 int x = 5; public void unsafe() { x = 5; x = x + 5; return x; } 

porque faz isso

 (in the thread's current frame) push "this" push 5 set member x push "this" get member x push 5 add integer set member x get member x return 

O último bytecode torna evidente que a intercalação de dois encadeamentos cria comunicações thread-to-thread usando o membro x um intermediário, enquanto o primeiro bloco de código não pode ter nenhuma comunicação inter-thread porque não há intermediários.

Atualmente, significa final da mesma forma que qualquer variável local, além de ser sempre “definitivamente atribuído”.

Em compilações recentes do JDK7, uma alteração de linguagem do Project Coin permite indicar um grau de tipagem estática implícita em andamento. Um único catch pode capturar diversas exceções verificadas por um tipo de base comum e relançar com o contexto que o contém, apenas pegando ou declarando as exceções que poderiam (estaticamente falando) ser lançadas dentro do try . (Veja o link para uma melhor explicação).

A final palavra-chave em variables ​​significa que a variável só pode ser atribuída uma vez, e como a atribuição aqui está sendo feita pelo compilador, isso significa que a variável não pode ser alterada posteriormente no código.

Esta é uma propriedade importante, pois significa para o mantenedor que essa variável em particular terá esse valor específico em todos os lugares em que é usada e não é necessário manter o controle de onde ela muda. Isso é reconhecido por ser tão útil que a ação “Limpar” no Eclipse permite adicionar “final” sempre que possível, e eu acredito que o que você vê é o resultado de uma limpeza automática, porque a maioria dos programadores humanos iria manter o bloco de captura curto, de modo que tal indicação não é necessária.

A pergunta: “O que finally faz?” é abordado em outras respostas a esta questão, e aqui , aqui e aqui . Mas, no contexto de um bloco try-catch , o Java Language Specification (JLS) §4.12.4 declara (ênfase minha):

  • Um recurso de uma instrução try-with-resources (§14.20.3) e um parâmetro de exceção de uma cláusula multi-catch (§14.20) são implicitamente declarados final .
  • Um parâmetro de exceção de uma cláusula uni-catch (§14.20) pode ser efetivamente final em vez de ser explicitamente declarado final. Esse parâmetro nunca é declarado implicitamente como final .

Em uma cláusula multi-catch :

Adicionar a palavra-chave final a uma cláusula multi-catch simplesmente explicita o fato de que a variable é implicitamente final. Em geral, sempre que a palavra-chave final fornecer informações adicionais que ajudem a tornar seu código mais legível / sustentável, use-o.

Em uma cláusula uni-catch

Por outro lado, o parâmetro de exceção em uma cláusula uni-catch nunca é implicitamente final. Portanto, usar a palavra-chave final para uma cláusula uni-catch evita que algo como o seguinte aconteça:

 try { throw new Exception(); catch (Exception e){ e = null; e.printStackTrace(); //throws a NullPointerException } 

A questão é óbvia neste exemplo simples. Mas dois casos podem ser menos óbvios e justificar o uso de finally :

  1. Se o bloco catch for mais complicado, a reatribuição acidental é possível. (Embora, se o bloco catch for complicado, provavelmente você está fazendo errado.)
  2. Para evitar problemas causados ​​durante a manutenção do código. Adicionar final à variável exception garantirá que a reconsignação seja detectada na compilation, em vez de Runtime

Como regra geral, use a palavra-chave final em uma cláusula uni-catch da mesma maneira que você usaria a palavra-chave final para um parâmetro de método :

JLS§ 4.12.4 : Declarar uma variável final pode servir como documentação útil de que seu valor não será alterado e pode ajudar a evitar erros de programação.