Como você define uma classe de constantes em Java?

90

Suponha que você precise definir uma classe em que tudo o que ela faz é manter constantes.

public static final String SOME_CONST = "SOME_VALUE";

Qual é a forma preferida de fazer isso?

  1. Interface
  2. Classe Abstrata
  3. Aula Final

Qual devo usar e por quê?


Esclarecimentos para algumas respostas:

Enums - não vou usar enums, não estou enumerando nada, apenas coletando algumas constantes que não estão relacionadas entre si de forma alguma.

Interface - não vou definir nenhuma classe como aquela que implementa a interface. Só quer usar a interface para chamar constantes assim: ISomeInterface.SOME_CONST.

Yuval Adam
fonte
Há alguma discussão semelhante aqui: stackoverflow.com/questions/320588/… . Eu usaria uma classe final com um construtor privado para que ela não pudesse ser instanciada.
Dan Dyer
2
Desculpe, mas "Não vou usar enums" transforma essa pergunta em "qual é a melhor maneira de fazer algo estúpido?"
cletus
Não estou dizendo que você vai implementar a interface. Mas não adianta usar uma interface para fazer isso. Então, vá com a aula final
:)
Qual é o problema com Enum? Você sempre pode usá-lo para coletar 'algumas constantes que não estão relacionadas entre si de forma alguma'. Hmm?
gedevan
6
Conceitualmente, um enum é uma escolha ruim se as constantes não estiverem relacionadas. Um enum representa valores alternativos do mesmo tipo. Essas constantes não são alternativas e podem nem ser do mesmo tipo (algumas podem ser strings, alguns inteiros, etc.)
Dan Dyer

Respostas:

94

Use uma aula final. para simplificar, você pode usar uma importação estática para reutilizar seus valores em outra classe

public final class MyValues {
  public static final String VALUE1 = "foo";
  public static final String VALUE2 = "bar";
}

em outra classe:

import static MyValues.*
//...

if(variable.equals(VALUE1)){
//...
}
user54579
fonte
4
Onde está a vantagem de criar uma classe separada aqui? Embora eu normalmente não considere a API Calendar como um bom exemplo de design, ela está bem em termos de "constantes relacionadas ao calendário estão na classe Calendar".
Jon Skeet
7
o benefício é não duplicar o código, caso você precise reutilizar constantes em mais de uma classe. Eu acho que você pode ver facilmente a vantagem disso.
user54579
2
Por que você duplicaria o código? Basta referir-se à outra classe. Acho relativamente raro que uma constante esteja realmente sozinha.
Jon Skeet
14
Para melhor legibilidade, eu também teria um construtor padrão privado sem corpo (e um comentário correspondente).
Ran Biron
5
Resposta bem antiga, e este comentário provavelmente está fora do lugar, mas eu usaria VALUE1.equals(variable)porque evita NPE.
Aakash
38

Seu esclarecimento afirma: "Não vou usar enums, não estou enumerando nada, apenas coletando algumas constantes que não estão relacionadas entre si de forma alguma."

Se as constantes não estão relacionadas entre si, por que você deseja agrupá-las? Coloque cada constante na classe com a qual está mais intimamente relacionada.

Jon Skeet
fonte
2
Jon - eles estão relacionados no sentido de que todos pertencem à mesma funcionalidade. No entanto, eles não são uma enumeração de nada ... Eles não possuem a propriedade de que um objeto é "uma daquelas coisas".
Yuval Adam
13
OK. Nesse caso, basta colocá-los na classe mais próxima da funcionalidade à qual estão relacionados.
Jon Skeet
28

Minhas sugestões (em ordem decrescente de preferência):

1) Não faça isso . Crie as constantes na classe real onde são mais relevantes. Ter uma classe / interface de 'conjunto de constantes' não segue as melhores práticas OO.

Eu, e todos os outros, ignoramos o nº 1 de vez em quando. Se você vai fazer isso:

2) classe final com construtor privado Isso irá pelo menos evitar que alguém abuse do seu 'saco de constantes' estendendo / implementando-o para obter fácil acesso às constantes. (Eu sei que você disse que não faria isso - mas isso não significa que alguém virá depois de você)

3) interface Isso funcionará, mas não é minha preferência dar a possível menção de abuso no item 2.

Em geral, só porque essas são constantes, não significa que você não deva aplicar os princípios normais de oo a elas. Se apenas uma classe se preocupa com uma constante - deve ser particular e pertencer àquela classe. Se apenas os testes se importam com uma constante - ela deve estar em uma classe de teste, não em código de produção. Se uma constante for definida em vários lugares (não apenas acidentalmente a mesma) - refatorar para eliminar a duplicação. E assim por diante - trate-os como se fosse um método.

kenj0418
fonte
2
O problema do 1 é que às vezes você injetará em seu código algumas dependências para outra classe de camada apenas para buscar a constante.
amdev
Todos os campos em uma interface são implicitamente públicos, estáticos e finais
Kodebetter
@Kodebetter Mas as interfaces podem ser estendidas / implementadas para adicionar mais campos.
Wit
12

Como Joshua Bloch observa em Effective Java:

  • As interfaces devem ser usadas apenas para definir tipos,
  • classes abstratas não impedem a instanciabilidade (elas podem ser subclasses e até mesmo sugerem que são projetadas para serem subclasses).

Você pode usar um Enum se todas as suas constantes estiverem relacionadas (como nomes de planetas), colocar os valores constantes nas classes às quais eles estão relacionados (se você tiver acesso a eles) ou usar uma classe de utilitário não instável (definir um construtor padrão privado) .

class SomeConstants
{
    // Prevents instanciation of myself and my subclasses
    private SomeConstants() {}

    public final static String TOTO = "toto";
    public final static Integer TEN = 10;
    //...
}

Então, como já foi dito, você pode usar importações estáticas para usar suas constantes.

Sébastien RoccaSerra
fonte
7

Meu método preferido é não fazer nada disso. A era das constantes praticamente morreu quando o Java 5 introduziu enums typesafe. E mesmo antes disso, Josh Bloch publicou uma versão (um pouco mais prolixa) disso, que funcionava no Java 1.4 (e anteriores).

A menos que você precise de interoperabilidade com algum código legado, não há mais razão para usar constantes String / inteiras nomeadas.

cletus
fonte
2
Boa resposta, um exemplo seria melhor.
amdev
3

Basta usar a aula final.

Se você quiser adicionar outros valores, use uma classe abstrata.

Não faz muito sentido usar uma interface, uma interface deve especificar um contrato. Você só deseja declarar alguns valores constantes.

Megacan
fonte
3

Enums não são a melhor escolha para esse tipo de coisa?

Boris Pavlović
fonte
2
99% do tempo. Mas não sempre.
L. Holanda
3

enums estão bem. IIRC, um item em Java eficaz (2ª Ed) tem enumconstantes enumerando opções padrão que implementam uma [palavra-chave Java] interfacepara qualquer valor.

Minha preferência é usar uma [palavra interface- chave Java] em vez final classde constantes for. Você obtém implicitamente o public static final. Algumas pessoas argumentarão que um interfacepermite que programadores ruins o implementem, mas programadores ruins irão escrever um código péssimo, não importa o que você faça.

Qual parece melhor?

public final class SomeStuff {
     private SomeStuff() {
         throw new Error();
     }
     public static final String SOME_CONST = "Some value or another, I don't know.";
}

Ou:

public interface SomeStuff {
     String SOME_CONST = "Some value or another, I don't know.";
}
Tom Hawtin - tackline
fonte
mas os programadores ruins escreverão um código péssimo, não importa o que você faça. Isso é verdade. Se você pode tomar medidas para atenuar a programação ruim ou eliminá-la completamente, então você tem um pouco de responsabilidade em fazer isso; seja o mais explícito possível. Um mau programador não pode estender uma aula final.
liltitus27 de
1
@ liltitus27 Até certo ponto, eu concordo. Mas você realmente quer um código feio apenas para impedir uma maneira de os programadores pobres escreverem códigos ruins? O código que eles produzem ainda será impossível, mas agora seu código está menos legível.
Tom Hawtin - tackline
1

Ou 4. Coloque-os na classe que contém a lógica que mais usa as constantes

... desculpe, não pude resistir ;-)

Simon Groenewolt
fonte
3
Isso não é uma boa ideia. Isso cria dependências entre classes que não deveriam ter nenhuma.
Yuval Adam
Por que não? Eu diria que classes que usam as mesmas constantes têm uma dependência de qualquer maneira ... E de alguma forma deve haver uma classe que é mais dependente dessas constantes.
Simon Groenewolt
Se houvesse apenas uma classe usando constantes, isso faria sentido.
Tom Hawtin - tackline
-1
  1. Uma das desvantagens do construtor privado é que o método nunca poderia ser testado.

  2. Enum pelo conceito de natureza bom para aplicar em tipo de domínio específico, aplicá-lo a constantes descentralizadas parece não bom o suficiente

O conceito de Enum é "Enumerações são conjuntos de itens intimamente relacionados".

  1. Estender / implementar uma interface constante é uma prática ruim, é difícil pensar sobre a necessidade de estender uma constante imutável em vez de se referir a ela diretamente.

  2. Se aplicarmos uma ferramenta de qualidade como SonarSource, existem regras que obrigam o desenvolvedor a abandonar a interface constante, isso é uma coisa estranha, pois muitos projetos apreciam a interface constante e raramente as coisas "estendidas" acontecem em interfaces constantes

Guizhou Feng
fonte
1
"construtor privado é a existência de método nunca poderia ser testado": não é verdade. Se você (ou seu chefe) for realmente paranóico sobre os relatórios de cobertura de código serem 100%, você ainda pode testar isso usando reflexão e garantindo que o construtor lance uma exceção. Mas, IMHO, isso é apenas formalidade e realmente não precisa ser testado. Se você (ou equipe) realmente se preocupa com o que é realmente importante, não é necessária uma cobertura de linha de 100%.
L. Holanda