Durante a fase de desenvolvimento, há certas variáveis que precisam ser corrigidas na mesma execução, mas podem precisar ser modificadas ao longo do tempo. Por exemplo, boolean
para sinalizar o modo de depuração, fazemos coisas no programa que normalmente não faríamos.
É mau estilo conter esses valores em uma constante, ou seja, final static int CONSTANT = 0
em Java? Eu sei que uma constante permanece a mesma durante o tempo de execução, mas também deveria ser a mesma durante todo o desenvolvimento, exceto para mudanças não planejadas, é claro?
Procurei perguntas semelhantes, mas não encontrei nada que correspondesse exatamente ao meu.
final
fornece uma garantia imposta pelo compilador de que o programa não modificará o valor. Eu não descartaria isso apenas porque o programador pode querer modificar o valor atribuído no código-fonte.gravity
meio do jogo / corrida. Eles não significam necessariamente quegravity
é o mesmo em todos os planetas ... Dito isto, a solução saudável é criargravity
uma constante, mas extraí-la de umplanet
arquivo ou banco de dados no início do escopo relevante.Respostas:
Em Java, as constantes finais estáticas podem ser copiadas, pelo compilador, como seus valores, no código que as utiliza . Como resultado disso, se você lançar uma nova versão do seu código e houver alguma dependência a jusante que usou a constante, a constante nesse código não será atualizada, a menos que o código a jusante seja recompilado. Isso pode ser um problema se eles fizerem uso dessa constante com código que espera o novo valor, pois mesmo que o código-fonte esteja correto, o código binário não esteja.
Essa é uma verruga no design do Java, já que é um dos poucos casos (talvez o único) em que a compatibilidade de origem e a compatibilidade binária não são iguais. Exceto nesse caso, você pode trocar uma dependência por uma nova versão compatível com a API, sem que os usuários da dependência precisem recompilar. Obviamente, isso é extremamente importante, dada a maneira como as dependências Java geralmente são gerenciadas.
Para piorar a situação, o código fará silenciosamente a coisa errada, em vez de produzir erros úteis. Se você substituísse uma dependência por uma versão com definições incompatíveis de classe ou método, obteria erros no carregador de classes ou na chamada, que pelo menos fornecem boas pistas sobre qual é o problema. A menos que você tenha alterado o tipo do valor, esse problema aparecerá apenas como um comportamento inadequado do tempo de execução misterioso.
O mais irritante é que as JVMs de hoje podem alinhar facilmente todas as constantes em tempo de execução sem penalidade no desempenho (além da necessidade de carregar a classe que define a constante, que provavelmente está sendo carregada de qualquer maneira), infelizmente a semântica do idioma data dos dias anteriores às JITs . E eles não podem mudar o idioma, porque o código compilado com os compiladores anteriores não estará correto. A compatibilidade com erros ocorre novamente.
Por causa disso tudo, algumas pessoas aconselham nunca alterar um valor final estático. Para bibliotecas que podem ser amplamente distribuídas e atualizadas de maneiras desconhecidas em momentos desconhecidos, essa é uma boa prática.
Em seu próprio código, especialmente no topo da hierarquia de dependências, você provavelmente se safará disso. Mas nesses casos, considere se você realmente precisa que a constante seja pública (ou protegida). Se a constante for apenas visibilidade do pacote, é razoável, dependendo de suas circunstâncias e padrões de código, que o pacote inteiro seja sempre recompilado de uma só vez, e o problema desaparecerá. Se a constante for privada, você não terá nenhum problema e poderá alterá-la quando quiser.
fonte
Qualquer coisa no seu código-fonte, incluindo
const
constantes globais declaradas, pode estar sujeita a alterações com uma nova versão do seu software.As palavras-chave
const
(oufinal
em Java) estão lá para sinalizar ao compilador que essa variável não será alterada enquanto esta instância do programa estiver em execução . Nada mais. Se você deseja enviar mensagens para o próximo mantenedor, use um comentário na fonte, é para isso que elas servem.É uma maneira muito melhor de se comunicar com seu futuro eu.
fonte
TaxRate
estarpublic
me deixa nervoso. Gostaria de ter certeza de que apenas o departamento de vendas foi impactado por essa alteração e não também nossos fornecedores que nos cobram um imposto. Quem sabe o que aconteceu na base de código desde que esse comentário foi escrito.public const
campos devem ser usados apenas para coisas que nunca serão alteradas, como Math.pi. Se você estiver criando uma biblioteca, as coisas que podem mudar durante o desenvolvimento ou com uma nova versão devem serpublic static readonly
, para não causar problemas aos usuários da sua biblioteca.Precisamos distinguir dois aspectos das constantes:
E depois há um terceiro tipo relacionado: variáveis cujo valor não muda, ou seja, nomes para um valor. A diferença entre essas variáveis imutáveis e uma constante é quando o valor é determinado / atribuído / inicializado: uma variável é inicializada em tempo de execução, mas o valor de uma constante é conhecido durante o desenvolvimento. Essa distinção é um pouco confusa, pois um valor pode ser conhecido durante o desenvolvimento, mas na verdade é criado apenas durante a inicialização.
Mas se o valor de uma constante for conhecido no tempo de compilação, o compilador poderá executar cálculos com esse valor. Por exemplo, a linguagem Java tem o conceito de expressões constantes . Uma expressão constante é qualquer expressão que consiste apenas em literais de primitivas ou cadeias, operações em expressões constantes (como conversão, adição, concatenação de cadeias) e em variáveis constantes. [ JLS §15.28 ] Uma variável constante é uma
final
variável que é inicializada com uma expressão constante. [JLS §4.12.4] Então, para Java, esta é uma constante em tempo de compilação:Isso se torna interessante quando uma variável constante é usada em várias unidades de compilação e, em seguida, a declaração é alterada. Considerar:
A.java
:B.java
:Agora, quando compilarmos esses arquivos, o
B.class
bytecode declarará um campoY = 9
porqueB.Y
é uma variável constante.Mas quando alteramos a
A.X
variável para um valor diferente (digamosX = 0
) e recompilamos apenas oA.java
arquivo,B.Y
ainda se refere ao valor antigo. Este estadoA.X = 0, B.Y = 9
é inconsistente com as declarações no código fonte. Feliz depuração!Isso não significa que as constantes nunca devem ser alteradas. As constantes são definitivamente melhores que os números mágicos que aparecem sem explicação no código fonte. No entanto, o valor de constantes públicas faz parte da sua API pública . Isso não é específico para Java, mas também ocorre em C ++ e outras linguagens que apresentam unidades de compilação separadas. Se você alterar esses valores, precisará recompilar todo o código dependente, ou seja, executar uma compilação limpa.
Dependendo da natureza das constantes, elas podem ter levado a suposições incorretas pelos desenvolvedores. Se esses valores forem alterados, eles podem acionar um bug. Por exemplo, um conjunto de constantes pode ser escolhido para formar certos padrões de bits, por exemplo
public static final int R = 4, W = 2, X = 1
. Se eles forem alterados para formar uma estrutura diferenteR = 0, W = 1, X = 2
, o código existenteboolean canRead = perms & R
ficará incorreto. E pense na diversão que resultariaInteger.MAX_VALUE
em mudar! Não há solução aqui, é apenas importante lembrar que o valor de algumas constantes é realmente importante e não pode ser alterado simplesmente.Mas para a maioria das constantes alterá-las, tudo ficará bem desde que as restrições acima sejam consideradas. Uma constante é segura para mudar quando o significado, e não o valor específico, é importante. É o caso, por exemplo, de ajustáveis como
BORDER_WIDTH = 2
ouTIMEOUT = 60; // seconds
ou modelos comoAPI_ENDPOINT = "https://api.example.com/v2/"
- embora, sem dúvida, alguns ou todos eles devam ser especificados nos arquivos de configuração, e não no código.fonte
Uma constante só é garantida como constante durante a vida útil do tempo de execução do aplicativo . Enquanto isso for verdade, não há razão para não tirar proveito do recurso de idioma. Você só precisa saber quais são as consequências para o uso de um sinalizador de constante versus compilador para o mesmo objetivo:
Tendo mantido um aplicativo que ativava o desenho de caixas delimitadoras de formas para podermos depurar como elas foram desenhadas, encontramos um problema. Após a refatoração, todo o código desativado pelos sinalizadores do compilador não seria compilado. Depois disso, intencionalmente alteramos nossos sinalizadores de compilador para constantes de aplicativo.
Estou dizendo isso para demonstrar que existem compensações. O peso de alguns booleanos não deixaria o aplicativo sem memória ou ocuparia muito espaço. Isso pode não ser verdade se a sua constante for realmente um objeto grande que essencialmente possui um identificador para tudo no seu código. Se não for necessário remover todas as referências que ele mantém sobre um objeto depois que ele não for mais necessário, seu objeto poderá ser a fonte de um vazamento de memória.
Não sou fã de simples declarações gerais, mas, em geral, seu colega sênior está correto. Se algo estiver sujeito a alterações frequentes, pode ser necessário que seja um item configurável. Por exemplo, você provavelmente poderia convencer seu colega por uma constante
IsInDebugMode = true
quando quiser proteger algum código contra quebra. No entanto, algumas coisas podem precisar mudar com mais frequência do que você libera um aplicativo. Se for esse o caso, você precisa de uma maneira de alterar esse valor no momento apropriado. Você pode pegar o exemplo de aTaxRate = .065
. Isso pode ser verdade no momento em que você compila seu código, mas devido a novas leis, ele pode ser alterado antes do lançamento da próxima versão do seu aplicativo. Isso é algo que precisa ser atualizado a partir de algum mecanismo de armazenamento (como arquivo ou banco de dados)fonte
#ifdef
es? Como eles se baseiam na substituição textual do código fonte, eles não fazem parte da semântica da linguagem de programação. Observe que o Java não possui um pré-processador.#ifdef
bandeiras. Embora eles não façam parte da semântica de C, eles fazem parte do C #. Eu estava escrevendo para o contexto maior do agnosticismo da linguagem.A
const
,#define
oufinal
é uma dica do compilador (observe que na#define
verdade não é uma dica, é uma macro e significativamente mais poderosa). Isso indica que o valor não será alterado durante a execução de um programa e várias otimizações podem ser feitas.No entanto, como uma dica do compilador, o compilador faz coisas que nem sempre são esperadas pelo programador. Em particular, o javac alinhará um
static final int FOO = 42;
para que, em qualquer lugar queFOO
seja usado, o código de bytes compilado real seja lido42
.Isso não é uma surpresa muito grande até que alguém mude o valor sem recompilar a outra unidade de compilação (arquivo .java) - e os
42
restos no código de bytes (veja é possível desabilitar o alinhamento de variáveis finais estáticas do javac? ).Fazer algo
static final
significa que é isso e para sempre será isso e mudá-lo é realmente um grande negócio - especialmente se não forprivate
.Constantes para coisas como
final static int ZERO = 0
não são um problema.final static double TAX_RATE = 0.55
(além de ser dinheiro e duplicar é ruim e deve estar usando o BigDecimal, mas não é um primitivo e, portanto, não está embutido) é um problema e deve ser examinado com muito cuidado para onde é usado.fonte
is a problem and should be examined with great care for where it is used.
Por que isso é um problema?Como o nome sugere, as constantes não devem ser alteradas durante o tempo de execução e, na minha opinião, as constantes são definidas para não serem alteradas por um longo período (você pode consultar esta questão de SO para obter mais informações.
Quando se trata de necessidade de sinalizadores (por exemplo, para o modo de desenvolvimento), você deve usar um arquivo de configuração ou um parâmetro de inicialização (muitos IDEs suportam a configuração de parâmetros de inicialização em uma base por projeto; consulte a documentação relevante) para ativar este modo - Dessa forma, você mantém a flexibilidade de usar esse modo e não se esqueça de alterá-lo sempre que o código for produtivo.
fonte
Ser capaz de mudar entre as execuções é um dos pontos mais importantes da definição de uma constante no seu código-fonte!
A constante fornece um local bem definido e documentado (em certo sentido) para alterar o valor sempre que necessário durante a vida útil do seu código-fonte. Também é uma promessa que mudar a constante nesse local realmente mudará todas as ocorrências do que quer que seja.
Como um exemplo adverso: não faria sentido ter uma constante
TRUE
que se avalietrue
em um idioma que realmente tenha atrue
palavra - chave. Você nunca, nem mesmo uma vez, declararia,TRUE=false
exceto como uma piada cruel.É claro que existem outros usos de constantes, por exemplo, abreviar código (
CO_NAME = 'My Great World Unique ACME Company'
), evitar duplicação (PI=3.141
), definir convenções (TRUE=1
) ou qualquer outra coisa, mas ter uma posição definida para alterar a constante é certamente um dos mais importantes.fonte