Por que a palavra-chave 'final' é usada tão pouco na indústria? [fechadas]

14

Desde que descobri os poderes da finalpalavra - chave em Java, alguns anos atrás, isso me ajudou a tornar meus códigos muito mais legíveis, pois as pessoas podem ver facilmente o que são variáveis ​​somente leitura. Também pode fornecer um pequeno impulso ao JIT e, embora seja muito limitado, não pode prejudicar, especialmente ao direcionar dispositivos incorporados, como plataformas Android.

Mas, acima de tudo, contribui para tornar um design mais robusto às alterações e orientar outros confirmadores quando eles precisarem modificar a base de código.

No entanto, ao navegar em parte do código-fonte do JDK, nunca encontrei essa palavra-chave, seja para classes, métodos ou variáveis. O mesmo se aplica a vários sistemas que tive que revisar.

Há uma razão? É um paradigma comum de design deixar tudo mutável por dentro?

Aurelien Ribon
fonte
em micro otimizações, estabelecendo finalcampos tem a mesma semântica como escrever um volatilecampo e, em seguida, lê-los mais tarde precisa ter semântica de leitura voláteis, isto nem sempre o que você quer
catraca aberração
5
@ catraca: Eu acho que isso é mais sobre tornar suas aulas imutáveis, como na programação funcional.
Jonas
@ Kwebble: Talvez o mais importante seja que as instâncias individuais de String sejam imutáveis.
MatrixFrog

Respostas:

9

Suspeito que o motivo pelo qual você não o veja é porque o JDK foi projetado para ser estendido (é a base a partir da qual todos os seus programas são criados). Não seria incomum o código do aplicativo fazer uso dele. Também não esperaria ver muito disso no código da biblioteca (já que as bibliotecas também são projetadas para extensão).

Tente dar uma olhada em alguns bons projetos de código aberto e acho que você encontrará mais.

Em contraste com o que você vê em Java, no mundo .NET, já ouvi muitas vezes o argumento de que os clases devem ser sealed(semelhantes aos finais aplicados a uma classe) por padrão, e que o desenvolvedor deve desmarcar explicitamente isto.

Steven Evers
fonte
2
Eu estava até me referindo a muitos membros privados ou protegidos de algumas classes JDK que obviamente "geram uma vez, nunca substituem" variáveis ​​de objeto. Particularmente no pacote de giro. Esses são candidatos perfeitos para 'final', pois a substituição por um ponteiro nulo levaria a erros ao usar os componentes.
Aurelien Ribon
1
@ Aurélien: Se isso faz você se sentir melhor, muitas das classes no .NET Framework são seladas, para a consternação de alguns usuários que gostariam de estender as classes do framework com suas próprias funcionalidades. No entanto, essa limitação pode ser atenuada usando métodos de extensão.
Robert Harvey
1
Eu acho que isso é mais sobre imutabilidade do que evitar extensão. Em outras palavras, o uso de finalem campos e não em métodos. Classes imutáveis ​​também podem ser projetadas para serem estendidas.
Jonas
15

O problema com o uso finalde transmitir que algo é só de leitura é que ele só realmente funciona para tipos primitivos gosto int, charetc. Todos os objetos em Java são na verdade se refere ao uso de um ponteiro (tipo de). Como resultado, quando você usa a finalpalavra-chave em um objeto, você está dizendo apenas que a referência é somente leitura, o próprio objeto ainda é mutável.

Poderia ter sido usado mais se realmente tornasse o objeto somente leitura. No C ++, é exatamente constisso que faz e, como resultado, é uma palavra-chave muito mais útil e muito usada.

Um lugar em que uso finalfortemente a palavra-chave é com parâmetros para evitar qualquer confusão criada por coisas como esta:

public void someMethod(FancyObject myObject) {
    myObject = new FancyObject();
    myObject.setProperty(7);
}
...
public static void main(final String[] args) {
    ...
    FancyObject myObject = new FancyObject();
    someOtherObject.someMethod(myObject);
    myObject.getProperty(); // Not 7!
}

Neste exemplo, parece óbvio por que isso não funciona, mas se someMethod(FancyObject)é grande e complicada, pode ocorrer confusão. Por que não evitá-lo?

Também faz parte dos padrões de codificação Sun (ou Oracle agora, eu acho).

Gyan tcp Gary Buyn
fonte
1
Se houve mais uso finalnas classes da API Java, a maioria dos objetos era imutável como em muitas bibliotecas Scala. A criação de campos de objetos finaltorna a classe imutável em muitos casos. Esse design já é usado em BigDecimale String.
Jonas
@ Jonas: Li a pergunta para saber mais sobre o ponto 4 da resposta de schmmd, já que ele estava dizendo "já que as pessoas podem ver facilmente o que são variáveis ​​somente leitura" e respondi de acordo. Talvez eu devesse ter incluído essa suposição na resposta.
Gyan aka Gary Buyn 15/09/11
Lembre-se de que há tempo em que você deseja reatribuir o parâmetro. Como exemplo, é aparar um parâmetro de string.
Steve Kuo
@ Steve Normalmente, crio uma nova variável a ser atribuída nessa situação.
Gyan aka Gary Buyn 15/09/11
1
@ Gary, para mim, pelo menos, é muito raro que bugs / confusão sejam causados ​​pela reatribuição de um parâmetro. Prefiro ter código livre de desorganização e aceitar a chance remota de reatribuir um parâmetro que está causando um bug. Apenas tenha cuidado ao escrever / modificar código.
Steve Kuo
4

Concordo que a finalpalavra - chave melhora a legibilidade. Torna muito mais fácil entender quando um objeto é imutável. No entanto, em Java, é extremamente detalhado, principalmente (na minha opinião) quando usado em parâmetros. Isso não quer dizer que as pessoas não devam usá-lo porque é detalhado, mas não o usam porque é detalhado.

Alguma outra linguagem, como scala, facilita muito as declarações finais ( val ). Nessas linguagens, as declarações finais podem ser mais comuns que as variáveis.

Observe que existem muitos usos diferentes da palavra-chave final. Sua postagem abrange principalmente os itens 2 e 3.

  1. Classes finais (JLS 8.1.1.2)
  2. Campos finais (JLS 8.3.1.2)
  3. Métodos finais (JLS 8.4.3.3)
  4. Variáveis ​​finais (JLS 4.12.4)
schmmd
fonte
2

Bem, para começar, as convenções oficiais do código Java não favorecem nem proíbem o uso específico de final. Ou seja, os desenvolvedores do JDK podem escolher da maneira que preferirem.

Não consigo ler a mente deles, mas para mim, a preferência por usar finalou não tem sido uma questão de foco. Uma questão de saber se tenho tempo suficiente para me concentrar completamente no código ou não .

  • Digamos, em um de meus projetos, poderíamos gastar uma média diária de 100 linhas de código. Nesse projeto, tive uma percepção distinta de finalum lixo que apenas obscurece coisas que já são expressas com clareza suficiente no código. Parece que os desenvolvedores do JDK também se enquadram nessa categoria.
     
    Por outro lado, era totalmente oposto em outro projeto, onde passamos uma hora em média em 100 linhas de código. Lá, me vi atirando finalcomo uma pistola mashine no meu e no código do outro - simplesmente porque era a maneira mais rápida de detectar uma intenção do cara que a escreveu antes de mim e, da mesma forma, a maneira mais rápida de comunicar minha própria intenção. o cara que trabalhará no meu código mais tarde.

Também pode fornecer um pequeno impulso ao JIT e, embora seja muito limitado, não pode prejudicar

Raciocínio como acima é escorregadio. Otimização prematura pode prejudicar; Donald Knuth chega a chamá-lo de "a raiz de todo mal" . Não deixe isso te prender. Escreva código idiota .

mosquito
fonte
2

Recentemente, descobri a alegria do recurso "Salvar ações" no Eclipse IDE. Posso forçá-lo a reformatar meu código, inserir @Overrideanotações ausentes e fazer algumas coisas bacanas, como remover parênteses desnecessários em expressões ou colocar finalpalavras - chave em todos os lugares automaticamente sempre que pressiono ctrl + S. Eu ativei alguns desses gatilhos e, rapaz, isso ajuda muito!

Acontece que muitos desses gatilhos agem como uma verificação rápida de sanidade do meu código.

  • Pretendia substituir um método, mas a anotação não apareceu quando eu bati ctrl + s? - talvez eu estraguei os tipos de parâmetros em algum lugar!
  • Alguns parênteses foram removidos do código ao salvar? - talvez essa expressão lógica seja muito difícil para um programador se familiarizar rapidamente. Caso contrário, por que eu adicionaria esses parênteses em primeiro lugar?
  • Esse parâmetro ou variável local não é final. Será que ela tem de mudar o seu valor?

Descobriu-se que quanto menos variáveis ​​mudam, menos problemas tenho no momento da depuração. Quantas vezes você seguiu o valor de alguma variável apenas para descobrir que ela muda de alguma forma, digamos 5 para 7? "Como diabos poderia ser ?!" você se pergunta e passa as próximas horas entrando e saindo de inúmeros métodos para descobrir que cometeu um erro em sua lógica. E, para corrigi-lo, é necessário adicionar mais um sinalizador, algumas condições e alterar cuidadosamente alguns valores aqui e ali.

Oh, eu odeio depurar! Cada vez que corro o depurador, sinto que meu tempo está se esgotando e preciso desesperadamente desse tempo para que pelo menos alguns dos meus sonhos de infância se tornem realidade! Para o inferno com a depuração! finals significa que não há mais mudanças misteriosas de valor. Mais finals => partes menos frágeis no meu código => menos erros => mais tempo para fazer coisas boas!

Quanto a finalclasses e métodos, eu realmente não me importo. Eu amo polimorfismo. Polimorfismo significa reutilização significa menos código significa menos bugs. A JVM faz um bom trabalho com a desirtualização e o método embutido de qualquer maneira, portanto, não vejo valor em eliminar possibilidades de reutilização de código para benefícios de desempenho insatisfatórios.


Ver todos esses finals no código é um pouco perturbador no começo e leva tempo para se acostumar também. Alguns dos meus colegas de equipe ainda ficam muito surpresos ao ver tantas finalpalavras-chave. Eu gostaria que houvesse uma configuração no IDE para colorir sintaxe especial. Eu ficaria feliz em mudar para um tom de cinza (como anotações) para que eles não fiquem muito perturbadores ao ler o código. Atualmente, o Eclipse tem uma cor separada para returne todas as outras palavras-chave, mas não para final.

Andrew Андрей Листочкин
fonte
1
Talvez você deva considerar procurar linguagens funcionais como OCaml ou F #. Esses idiomas tendem a exigir muito menos depuração, um dos motivos é que tudo é somente leitura por padrão. Simplificando, uma vez atribuída, uma variável em uma linguagem funcional não muda.
Abel
1
Sim, eu sei disso e, na verdade, escrevo algum código ML de tempos em tempos - foi daí que me inspirei :) Não é sobre o idioma que você usa, mas sobre os princípios e técnicas que você aplica. Pode-se tornar imperativo com Haskell e donotação :) Certamente, Java não é a melhor linguagem para escrever em estilo funcional, mas pelo menos permite que você escreva um código robusto - e é com isso que realmente me importo.
Andrew Андрей Листочкин