Palavra-chave “final” de uso excessivo em Java [duplicado]

93

Enquanto eu entendo o que a palavra-chave final é usada no contexto de classes e métodos, bem como a intenção de seu uso no que diz respeito às variáveis; no entanto, o projeto que eu comecei a trabalhar parece ter um número excessivo deles e estou curioso sobre a lógica por trás dele.

O snippet de código a seguir é apenas um pequeno exemplo, pois não vejo muito sentido na palavra-chave final para as variáveis key e value :

private <K, V> Collection<V> getValuesForKeys(
    final Map<K, V> map, final Collection<K> keys) 
{
    final Collection<V> values = new ArrayList<V>(keys.size());
    for (final K key : keys) {
        final V value = map.get(key);
        if (value != null) {
            values.add(value);
        }
    }
    return values;
}

Eu tenho lido um pouco o uso dos artigos que encontrei no Google; no entanto, o padrão realmente faz coisas como ajudar o compilador a otimizar o código?

    
por rjzii 04.08.2011 / 20:27
fonte

6 respostas

102

Existem muitas referências que sugerem um liberal use of final . A especificação da linguagem Java tem uma seção sobre variáveis finais . Várias regras em ferramentas de análise estática também suportam isso - PMD tem até um número de regras para detectar quando o final pode ser usado . As páginas que eu criei forneceram um número de pontos sobre o que final faz e por que você deveria usá-lo liberalmente.

Para mim, o uso liberal de final realizou duas coisas na maioria dos códigos, e essas provavelmente são as coisas que levaram o autor do seu exemplo de código a usá-lo:

  1. Ele torna a intenção do código muito mais clara e leva ao código de autodocumentação. Usar final impede que o valor de um objeto primitivo seja alterado ou que um novo objeto seja feito e sobrescreve um objeto existente. Se não houver necessidade de alterar o valor de uma variável e alguém o fizer, o IDE e / ou o compilador fornecerão um aviso. O desenvolvedor deve corrigir o problema ou remover explicitamente o modificador final da variável. De qualquer forma, o pensamento é necessário para garantir que o resultado pretendido seja alcançado.

  2. Dependendo do seu código, ele serve como uma dica para o compilador potencializar as otimizações. Isso não tem nada a ver com o tempo de compilação, mas com o que o compilador pode fazer durante a compilação. Também não é garantido fazer nada. No entanto, sinalizar ao compilador que o valor dessa variável ou o objeto referido por essa variável nunca será alterado poderia permitir otimizações de desempenho.

Existem outras vantagens também, relacionadas à concorrência. Quando aplicado em nível de classe ou método, tem a ver com garantir o que pode ser substituído ou herdado. No entanto, eles estão além do escopo do seu exemplo de código. Mais uma vez, os artigos que eu criei foram muito mais detalhados sobre como você pode aplicar final .

A única maneira de ter certeza do motivo pelo qual o autor do código decidiu usar final é encontrar o autor e perguntar por si mesmo.

    
por 04.08.2011 / 21:08
fonte
30

Os principais benefícios de "final" em minha mente são duplos:

  • As variáveis finais são "mais seguras" do que as variáveis não finais, porque, uma vez vinculadas, nunca há uma dúvida sobre qual é o estado atual delas.
  • Por causa do acima, fazer uma variável final alivia o programador do excesso de malabarismo mental - ele / ela não precisa varrer o código para ver se a variável mudou. Esse estado de coisas feliz será familiar para qualquer pessoa que tenha passado algum tempo em um ambiente de linguagem funcional.

Quanto a este exemplo específico, pode ser que o programador tenha escolhido o hábito "final" e apenas aplique a palavra-chave "final" em todos os lugares, como é óbvio. (Sou cético quanto à noção de que a palavra-chave final ajudaria o compilador ao falar sobre atribuições individuais - certamente não precisa da ajuda para determinar se apenas uma tarefa ocorreu?)

Eu sou da opinião de que o Java o fez de trás para frente - não deve haver nenhuma palavra-chave "final" para variáveis, tudo deve ser "final" por padrão e se você quiser uma variável mutável você deve adicionar uma palavra-chave para isso ("var" ou alguns desses). (Como outro comentarista mencionou, scala tem duas palavras-chave - "val" e "var" para variáveis finais e não finais, respectivamente - eu aceito).

    
por 05.08.2011 / 07:56
fonte
11

Em Java, o único lugar onde eu sei onde a palavra-chave final é necessária é disponibilizar uma variável confiável para uma classe anônima (já que o compilador faz alguns truques embaixo das capas exigindo que isso valor não pode mudar).

É - ao meu conhecimento - um mito de que a palavra-chave final permite ao compilador Java otimizar o código, já que todas as otimizações que importam acontecem na parte JIT do tempo de execução.

É, portanto, uma questão de gosto. Há, no entanto, um benefício muito significativo para usar muitas finais, a saber, tornar o código mais fácil de ler para futuros mantenedores.

Marcando uma variável como final informa ao leitor que essa variável nunca, nunca muda quando atribuída. Isto é muito importante ao ler o código como você sabe quando você precisa saber o valor da variável que é o mesmo que na atribuição inicial e não precisa analisar mentalmente todo o código entre para ver se a variável é designada novamente com outra coisa.

Além disso, se você ver que uma variável não está marcada com final , você sabe que ela será alterada em ! Esta é uma informação extremamente importante que pode ser transmitida ao leitor simplesmente com cinco caracteres faltando.

Qualquer coisa que possa ajudar o mantenedor a fazer seu trabalho mais rápido e de forma mais confiável, significa que o aplicativo é mais barato de manter! Em outras palavras, final economiza dinheiro real.

Nota: O Eclipse possui uma opção de "limpeza de fonte" que pode inserir finais sempre que possível. Isso pode ser útil tanto para escrever um novo código quanto para manter o antigo (inserir finais, se algum deles estiver faltando, a variável será alterada após a designação inicial). Minha intuição é que isso é o que o autor original descobriu e decidiu usar.

O assunto é discutido em mais detalhes no link

    
por 08.08.2011 / 19:17
fonte
6

Acho que a resposta para isso é mais simples do que outros sugerem. Não se trata de intenção ou design. Um bom tempo atrás, era verdade que adicionar final em alguns lugares (particularmente, para métodos e classes) permitia que a JVM otimizasse de forma mais agressiva. Como resultado, algumas pessoas ficaram furiosas e colocaram a final literalmente em todos os lugares para tentar fazer com que o código fosse mais rápido.

Devo acrescentar que não é o compilador, mas a JVM que faz a otimização. Além disso, duvido que colocar a final em uma variável local teria feito alguma diferença no desempenho.

Por fim, usar o final provavelmente não faria muita diferença nos dias de hoje, já que as otimizações da JVM avançaram um pouco.

    
por 04.08.2011 / 23:02
fonte
1

Parece-me que a palavra-chave final está sendo usada neste contexto para fazer uma coleção imutável. Coleções imutáveis são mais simples de raciocinar e mais seguras de serem usadas em programas que exigem concorrência (vários encadeamentos ).

Não é verdade, claro. A palavra-chave final apenas garante que a referência à coleção não possa ser substituída por uma referência a uma coleção diferente ou nula.

    
por 04.08.2011 / 21:03
fonte
-2

Em uma aula, final impede que seja estendido. Também impede que um usuário substitua um método em uma subclasse. Você faria isso para proteger a funcionalidade da sua turma ou impedir que alguém interferisse com a maneira básica como ela funciona. Também é mais eficiente depois de compilado - não sei exatamente como no momento, apenas sei que é.

Você o usaria para uma variável como abreviação de um valor. Este é o substituto de java para o valor de nome cde / c #define ou a palavra-chave const. A principal razão pela qual você faz isso é aumentar a legibilidade e poupar o trabalho de gravar um valor várias vezes em seu código. Especialmente porque quando você deseja alterar esse valor, você teria que alterá-lo em todos os lugares. A palavra-chave final garante que você não possa alterar acidentalmente seu valor em outro lugar em seu código.

Parece ser excessivo no código que você postou acima.

Além disso, obviamente é diferente de c ++, no sentido de que um valor de const não pode ser alterado dentro de um método, enquanto este obviamente está sendo alterado.

Além disso, quando uma variável é definida para final, ela garante a segurança do thread, pois é impossível gravar no valor.

    
por 04.08.2011 / 20:38
fonte