Qual è il modo migliore per implementare le costanti in Java? [chiuso]


372

Ho visto esempi come questo:

public class MaxSeconds {
   public static final int MAX_SECONDS = 25;
}

e supponevo che avrei potuto avere una classe Costanti in cui avvolgere le costanti, dichiarandole finale statico. Non conosco praticamente Java e mi chiedo se questo sia il modo migliore per creare costanti.


1
solo per aggiungere java costanti: pubblico / privato
ms_27

Risposte:


403

Questo è perfettamente accettabile, probabilmente anche lo standard.

(public/private) static final TYPE NAME = VALUE;

dove TYPEè il tipo, NAMEè il nome in maiuscolo con caratteri di sottolineatura per gli spazi ed VALUEè il valore costante;

Consiglio vivamente di NON inserire le costanti nelle proprie classi o interfacce.

Come nota a margine: le variabili dichiarate definitive e mutabili possono ancora essere modificate; tuttavia, la variabile non può mai puntare su un oggetto diverso.

Per esempio:

public static final Point ORIGIN = new Point(0,0);

public static void main(String[] args){

    ORIGIN.x = 3;

}

Questo è legale e ORIGINsarebbe quindi un punto in (3, 0).


19
Puoi persino "importare MaxSeconds.MAX_SECONDS statici;" in modo da non doverlo pronunciare MaxSeconds.MAX_SECONDS
Aaron Maenpaa,

23
Il commento precedente sull'importazione statica si applica solo a Java 5+. Alcuni ritengono che la stenografia non meriti la possibile confusione su da dove provenga la costante, quando si legge il codice lungo, MaxSeconds.MAX_SECONDS potrebbe essere più facile da seguire, quindi salire e guardare le importazioni.
MetroidFan2002,

5
Perché puoi cambiare l'oggetto come hanno mostrato jjnguy, è meglio se i tuoi costanti sono oggetti immutabili o semplici primitive / stringhe.
marcospereira,

14
Se stai leggendo questa domanda, leggi le seguenti due risposte prima di prendere questa risposta troppo sul serio, nonostante sia accettata è controversa se non sbagliata.
orbfish,

3
@jjnguy non ti sbagli, ma se leggessi solo la domanda e le prime due righe della tua risposta, avrei l'impressione che "una classe Costanti" sia "perfettamente accettabile, probabilmente anche lo standard". Questa nozione è sbagliata.
Zach Lysobey,

235

Consiglio vivamente di non avere una singola classe di costanti. Può sembrare una buona idea al momento, ma quando gli sviluppatori si rifiutano di documentare le costanti e la classe cresce fino a comprendere fino a 500 costanti che non sono affatto correlate tra loro (essendo correlate a aspetti completamente diversi dell'applicazione), questo generalmente si trasforma in un file costanti completamente illeggibile. Anziché:

  • Se hai accesso a Java 5+, usa enum per definire le tue costanti specifiche per un'area di applicazione. Tutte le parti dell'area di applicazione devono fare riferimento agli enum, non ai valori costanti, per queste costanti. Puoi dichiarare un enum simile a come dichiari una classe. Gli enum sono forse la caratteristica più (e, probabilmente, unica) utile di Java 5+.
  • Se hai costanti valide solo per una determinata classe o una delle sue sottoclassi, dichiarale come protette o pubbliche e inseriscile nella classe superiore nella gerarchia. In questo modo, le sottoclassi possono accedere a questi valori costanti (e se altre classi accedono ad essi tramite pubblico, le costanti non sono valide solo per una particolare classe ... il che significa che le classi esterne che usano questa costante potrebbero essere troppo strettamente accoppiate alla classe contenente la costante)
  • Se si dispone di un'interfaccia con comportamento definito, ma i valori restituiti oi valori dell'argomento dovrebbero essere particolari, è perfettamente accettabile definire costanti su tale interfaccia in modo che altri implementatori possano accedervi. Tuttavia, evita di creare un'interfaccia solo per contenere le costanti: può peggiorare quanto una classe creata solo per contenere le costanti.

12
sono assolutamente d'accordo ... questo può essere documentato come un classico modello anti-modello per grandi progetti.
Das

30
Fuori tema, ma ... I generici certamente non sono perfetti, ma penso che potresti fare un buon caso perché sono una caratteristica utile di Java 5 :)
Martin McNulty,

3
@ ŁukaszL. La domanda stessa è in realtà basata sull'opinione (ogni volta che si presenta "migliore", in genere è una questione di opinione), quindi la risposta è una risposta valida a questa domanda. Ho dato una risposta su quale (sì, credo di essere, quindi sì, è un'opinione, perché di nuovo il "migliore" cambia con il tempo ed è generalmente basato sull'opinione) il modo migliore per implementare le costanti in Java è.
MetroidFan2002,

1
Nessuna delle opzioni sopra ti dà una vera variabile globale. E se avessi qualcosa che viene usato ovunque ma non è un enum? Faccio un enumerazione di una sola cosa?
markthegrea,

1
Se hai bisogno di una costante globale che copra tutti i moduli, probabilmente c'è qualcosa che non va nella tua strategia di progettazione. Se hai davvero bisogno di una costante globale, creane una classe finale pubblica per il pacchetto di livello superiore e incollala lì. Quindi eliminalo non appena ti rendi conto che non tutte le tue classi hanno effettivamente bisogno di quella costante e spostala nel pacchetto che fa maggiormente riferimento. Puoi condividere una costante tra i pacchetti, ma è un odore di codice richiedere una costante globale che non sia un tipo enumerato, poiché i tipi enumerati possono avere un comportamento, ma una stringa è una stringa, un int è un int, ecc.
MetroidFan2002

120

È UNA CATTIVA PRATICA usare le interfacce solo per contenere le costanti (chiamato modello di interfaccia costante di Josh Bloch). Ecco cosa consiglia Josh:

Se le costanti sono fortemente legate a una classe o interfaccia esistente, è necessario aggiungerle alla classe o all'interfaccia. Ad esempio, tutte le classi primitive numeriche inscatolate, come Integer e Double, esportano le costanti MIN_VALUE e MAX_VALUE. Se le costanti vengono visualizzate al meglio come membri di un tipo enumerato, è necessario esportarle con un tipo enum . Altrimenti, è necessario esportare le costanti con una classe di utilità non affidabile.

Esempio:

// Constant utility class
package com.effectivejava.science;
public class PhysicalConstants {
    private PhysicalConstants() { }  // Prevents instantiation

    public static final double AVOGADROS_NUMBER   = 6.02214199e23;
    public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
    public static final double ELECTRON_MASS      = 9.10938188e-31;
}

Informazioni sulla convenzione di denominazione:

Per convenzione, tali campi hanno nomi costituiti da lettere maiuscole, con parole separate da caratteri di sottolineatura. È fondamentale che questi campi contengano valori primitivi o riferimenti a oggetti immutabili.


23
Se hai intenzione di chiamare qualcosa di cattiva pratica, forse dovresti spiegare perché pensi che sia?
GlennS,

14
Questo è un vecchio post, ma è meglio usare la abstractnotazione per la classe invece del costruttore privato.
Xtreme Biker,

5
Matt, mentre la raccomandazione del motociclista non è falsa, raccomanderei le lezioni finali, piuttosto che le lezioni astratte. il punto del motociclista nel dire che volevi assicurarti che la tua classe di costanti non fosse modificabile. Quindi, contrassegnandolo come finale, non si consente che venga sottoclassato o istanziato. Questo aiuta anche a incapsulare la sua funzionalità statica e non consente ad altri sviluppatori di sottoclassarlo e fargli fare cose che non è stato progettato per fare.
liltitus27,

7
@XtremeBiker Contrassegnare la classe abstractinvece di un costruttore privato non impedisce completamente l'istanza, perché si potrebbe sottoclassarla e creare un'istanza della sottoclasse (non che sia una buona idea farlo, ma è possibile). @ToolmakerSteve Non è possibile sottoclassare una classe con un costruttore privato (almeno non senza un grosso hack grave), perché il costruttore della sottoclasse deve chiamare il costruttore (ora privato) della sua superclasse. Quindi, contrassegnarlo non finalè necessario (ma forse più esplicito).
Importa questo

3
È anche peggio usare la classe solo per contenere le costanti. Se non vuoi mai creare un oggetto di quella classe, perché usi la classe normale in primo luogo?
MaxZoom,

36

In Effective Java (2a edizione), si consiglia di utilizzare enum anziché ints statici per le costanti.

C'è un buon commento sugli enum in Java qui: http://java.sun.com/j2se/1.5.0/docs/guide/language/enums.html

Si noti che alla fine di quell'articolo la domanda posta è:

Quindi, quando dovresti usare enums?

Con una risposta di:

Ogni volta che hai bisogno di un set fisso di costanti


21

Evita semplicemente di usare un'interfaccia:

public interface MyConstants {
    String CONSTANT_ONE = "foo";
}

public class NeddsConstant implements MyConstants {

}

È allettante, ma viola l'incapsulamento e offusca la distinzione delle definizioni di classe.


1
In effetti, le importazioni statiche sono di gran lunga preferibili.
Aaron Maenpaa,

1
Questa pratica è uno strano uso delle interfacce, che intendono dichiarare i servizi forniti da una classe.
Rafa Romero,

1
Non sono in disaccordo con l'evitare l'uso dell'interfaccia per le costanti, ma credo che il tuo esempio sia fuorviante. Non è necessario implementare l'interfaccia per accedere alla costante perché è implicitamente statica, pubblica e finale. Quindi, è più semplice di quanto tu abbia descritto qui.
Djangofan,

È vero ... sta violando l'incapsulamento, preferisco usare la classe Constant finale che sembra più orientata agli oggetti e preferibile all'interfaccia OR enum . Nota: Enum può essere evitato se Android non è necessario.
CoDe

19

Uso il seguente approccio:

public final class Constants {
  public final class File {
    public static final int MIN_ROWS = 1;
    public static final int MAX_ROWS = 1000;

    private File() {}
  }

  public final class DB {
    public static final String name = "oups";

    public final class Connection {
      public static final String URL = "jdbc:tra-ta-ta";
      public static final String USER = "testUser";
      public static final String PASSWORD = "testPassword";

      private Connection() {}
    }

    private DB() {}
  }

  private Constants() {}
}

Che, per esempio, io uso Constants.DB.Connection.URLper ottenere costante. Sembra più "orientato agli oggetti" quanto a me.


4
Interessante, ma ingombrante. Perché non dovresti invece creare costanti nella classe più strettamente associate a loro, come raccomandato da altri? Ad esempio, nel tuo codice DB altrove hai una classe base per le tue connessioni? Ad esempio "ConnectionBase". Quindi puoi inserire le costanti lì. Qualsiasi codice che funziona con le connessioni probabilmente avrà già un'importazione tale che può semplicemente dire "ConnectionBase.URL" anziché "Constants.DB.Connection.URL".
ToolmakerSteve

3
@ToolmakerSteve Ma che dire delle costanti generali che possono utilizzare più classi? ad esempio stili, URL dei servizi web, ecc ...?
Daniel Gomez Rico,

Mettere tutte le costanti in una classe ha un vantaggio: la manutenzione. Sai sempre esattamente dove trovare le costanti. Non sto dicendo che questo migliora questa tecnica, sto solo fornendo un vantaggio. E quello che @ albus.ua ha fatto è stato categorizzato le sue costanti, il che è una buona idea soprattutto se la classe delle costanti contiene molti molti valori costanti. Questa tecnica aiuterà a mantenere la classe gestibile e aiuta a descrivere meglio lo scopo della costante.
Nelda.techspiress,

17

La creazione di costanti finali statiche in una classe separata può metterti nei guai. Il compilatore Java lo ottimizzerà effettivamente e inserirà il valore effettivo della costante in qualsiasi classe che lo fa riferimento.

Se in seguito cambi la classe "Costanti" e non esegui una dura ricompilazione su altre classi che fanno riferimento a quella classe, finirai con una combinazione di vecchi e nuovi valori utilizzati.

Invece di pensare a queste come costanti, pensale come parametri di configurazione e crea una classe per gestirle. I valori devono essere non definitivi e prendere in considerazione l'uso dei getter. In futuro, poiché si determina che alcuni di questi parametri dovrebbero essere configurabili dall'utente o dall'amministratore, sarà molto più facile farlo.


+1 per questo avvertimento eccellente. (Se non puoi garantire che sia una costante permanente, considera invece un getter, come menziona big_peanut_horse.) Lo stesso vale con const in C #, a proposito: msdn.microsoft.com/en-us/library/e6w8fe1b.aspx
Jon Coombs,

13

L'errore numero uno che puoi fare è la creazione di una classe accessibile a livello globale chiamata con un nome generico, come Costanti. Questo viene semplicemente disseminato di immondizia e perdi tutta la capacità di capire quale parte del tuo sistema utilizza queste costanti.

Invece, le costanti dovrebbero andare nella classe che le "possiede". Hai una costante chiamata TIMEOUT? Probabilmente dovrebbe andare nella tua classe Communications () o Connection (). MAX_BAD_LOGINS_PER_HOUR? Entra in Utente (). E così via e così via.

L'altro possibile utilizzo sono i file .properties Java quando "costanti" possono essere definiti in fase di esecuzione, ma non possono essere facilmente modificati dall'utente. Puoi impacchettarli nei tuoi .jars e fare riferimento a loro con Class resourceLoader.


E, naturalmente, non vorrai mai accedere a una costante di più di una classe o evitare disordine nella parte superiore di una classe.
orbfish

6

Questa è la strada giusta da percorrere.

Generalmente le costanti non vengono mantenute in classi "Costanti" separate perché non sono rilevabili. Se la costante è rilevante per la classe corrente, tenerla lì aiuta lo sviluppatore successivo.



5

Preferisco usare getter piuttosto che costanti. Quei getter potrebbero restituire valori costanti, ad esempio public int getMaxConnections() {return 10;}, ma tutto ciò che necessita della costante passerà attraverso un getter.

Un vantaggio è che se il tuo programma supera la costante - scopri che deve essere configurabile - puoi semplicemente cambiare il modo in cui il getter restituisce la costante.

L'altro vantaggio è che per modificare la costante non è necessario ricompilare tutto ciò che la utilizza. Quando si fa riferimento a un campo finale statico, il valore di quella costante viene compilato in qualsiasi bytecode che lo fa riferimento.


5
Ben ricompilare le classi di riferimento non è certo un peso nel 21 ° secolo. E non dovresti mai usare il modello accessor / mutator (getter / setter) per cose diverse dall'accesso e dalla mutazione delle variabili membro. Le costanti sono concettualmente pensate per essere immediatamente di natura, mentre getter / setter sono (entrambi) pensati per gestire lo stato . Inoltre, stai solo chiedendo confusione: le persone non si aspetteranno che un getter produca una mera costante.

5

Sono d'accordo che l'uso di un'interfaccia non è la strada da percorrere. Evitare questo schema ha anche un suo oggetto (# 18) in Effch Java di Bloch .

Un argomento di Bloch contro il modello di interfaccia costante è che l'uso delle costanti è un dettaglio di implementazione, ma l'implementazione di un'interfaccia per usarle espone quel dettaglio di implementazione nell'API esportata.

Il public|private static final TYPE NAME = VALUE;modello è un buon modo per dichiarare una costante. Personalmente, penso che sia meglio evitare di creare una classe separata per ospitare tutte le tue costanti, ma non ho mai visto un motivo per non farlo, a parte le preferenze e lo stile personali.

Se le costanti possono essere ben modellate come enumerazione, considerare la struttura di enum disponibile in 1.5 o successive.

Se stai utilizzando una versione precedente alla 1.5, puoi comunque eseguire il pull delle enumerazioni typesafe usando le normali classi Java. (Vedi questo sito per ulteriori informazioni al riguardo).


Alcune costanti possono essere utilizzate per chiamare un'API. Ad esempio, consultare l'interfaccia org.springframework.transaction.TransactionDefinition. Ha un elenco di costanti come int PROPAGATION_REQUIRED = 0;
Borjab,

So che questo è vecchio, ma il collegamento a Effch Java di Bloch è interrotto. Potresti fornire un altro o un altro riferimento a sostegno del fatto che "l'utilizzo di un'interfaccia non è la strada da percorrere" per favore?
Nelda.techspiress,

4

Sulla base dei commenti sopra, penso che questo sia un buon approccio per cambiare la classe costante globale vecchio stile (con variabili finali statiche pubbliche) nel suo equivalente enumatico in un modo come questo:

public class Constants {

    private Constants() {
        throw new AssertionError();
    }

    public interface ConstantType {}

    public enum StringConstant implements ConstantType {
        DB_HOST("localhost");
        // other String constants come here

        private String value;
        private StringConstant(String value) {
            this.value = value;
        }
        public String value() {
            return value;
        }
    }

    public enum IntConstant implements ConstantType {
        DB_PORT(3128), 
        MAX_PAGE_SIZE(100);
        // other int constants come here

        private int value;
        private IntConstant(int value) {
            this.value = value;
        }
        public int value() {
            return value;
        }
    }

    public enum SimpleConstant implements ConstantType {
        STATE_INIT,
        STATE_START,
        STATE_END;
    }

}

Quindi posso riferirli a come:

Constants.StringConstant.DB_HOST

4
Perché? Come è un miglioramento? Ogni riferimento è ora ingombrante (Constants.StringConstant.whatever). IMHO, stai percorrendo una strada accidentata qui.
ToolmakerSteve

3

Un buon design orientato agli oggetti non dovrebbe richiedere molte costanti disponibili al pubblico. La maggior parte delle costanti dovrebbe essere incapsulata nella classe che ne ha bisogno per fare il suo lavoro.


1
O iniettato in quella classe tramite il costruttore.
WW.

2

C'è una certa quantità di opinione per rispondere a questo. Per cominciare, le costanti in Java sono generalmente dichiarate pubbliche, statiche e finali. Di seguito sono riportati i motivi:

public, so that they are accessible from everywhere
static, so that they can be accessed without any instance. Since they are constants it
  makes little sense to duplicate them for every object.
final, since they should not be allowed to change

Non userei mai un'interfaccia per un accessorio / oggetto CONSTANTS semplicemente perché ci si aspetta che le interfacce siano implementate. Non sarebbe divertente:

String myConstant = IMyInterface.CONSTANTX;

Invece sceglierei tra alcuni modi diversi, basato su alcuni piccoli compromessi, e quindi dipende da ciò di cui hai bisogno:

1.  Use a regular enum with a default/private constructor. Most people would define 
     constants this way, IMHO.
  - drawback: cannot effectively Javadoc each constant member
  - advantage: var members are implicitly public, static, and final
  - advantage: type-safe
  - provides "a limited constructor" in a special way that only takes args which match
     predefined 'public static final' keys, thus limiting what you can pass to the
     constructor

2.  Use a altered enum WITHOUT a constructor, having all variables defined with 
     prefixed 'public static final' .
  - looks funny just having a floating semi-colon in the code
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you still have to put explicit 'public static final' before each variable
  - drawback: not type-safe
  - no 'limited constructor'

3.  Use a Class with a private constructor:
  - advantage: you can JavaDoc each variable with an explanation
  - drawback: you have to put explicit 'public static final' before each variable
  - you have the option of having a constructor to create an instance
     of the class if you want to provide additional functions related
     to your constants 
     (or just keep the constructor private)
  - drawback: not type-safe

4. Using interface:
  - advantage: you can JavaDoc each variable with an explanation
  - advantage: var members are implicitly 'public static final'
  - you are able to define default interface methods if you want to provide additional
     functions related to your constants (only if you implement the interface)
  - drawback: not type-safe

2

Qual è il modo migliore per implementare le costanti in Java?

Un approccio che dovremmo davvero evitare : usare le interfacce per definire le costanti.

La creazione di un'interfaccia specifica per dichiarare le costanti è davvero la cosa peggiore: sconfigge il motivo per cui sono state progettate le interfacce: la definizione del contratto di metodo.

Anche se esiste già un'interfaccia per rispondere a un'esigenza specifica, dichiarare le costanti in esse non ha davvero senso in quanto le costanti non dovrebbero far parte dell'API e del contratto fornito alle classi client.


Per semplificare, abbiamo ampiamente 4 approcci validi .

Con static final String/Integercampo:

  • 1) usando una classe che dichiara le costanti all'interno ma non solo.
  • 1 variante) creando una classe dedicata a dichiarare solo le costanti.

Con Java 5 enum:

  • 2) dichiarare l'enum in una classe di scopo correlata (quindi come classe nidificata).
  • 2 variante) creando l'enum come classe autonoma (così definita nel suo file di classe).

TLDR: qual è il modo migliore e dove individuare le costanti?

Nella maggior parte dei casi, il modo enum è probabilmente più fine del static final String/Integermodo e personalmente penso che il static final String/Integermodo in cui dovrebbe essere usato solo se abbiamo buone ragioni per non usare enum.
E su dove dovremmo dichiarare i valori costanti, l'idea è di cercare se esiste una singola classe esistente che possiede una coesione funzionale specifica e forte con valori costanti. Se troviamo una tale classe, dovremmo usarla come detentore di costanti . Altrimenti, la costante non dovrebbe essere associata a nessuna classe particolare.


static final String/ static final Integercontroenum

L'utilizzo di Enums è davvero un modo per essere fortemente considerato.
Gli enum hanno un grande vantaggio sul campo Stringo Integercostante.
Stabiliscono un vincolo di compilazione più forte. Se si definisce un metodo che accetta l'enum come parametro, è possibile passare solo un valore enum definito nella classe enum (o null).
Con String e Integer puoi sostituirli con qualsiasi valore di tipo compatibile e la compilazione andrà bene anche se il valore non è una costante definita nei campi static final String/ static final Integer.

Ad esempio, sotto due costanti definite in una classe come static final Stringcampi:

public class MyClass{

   public static final String ONE_CONSTANT = "value";
   public static final String ANOTHER_CONSTANT = "other value";
   . . .
}

Ecco un metodo che prevede di avere una di queste costanti come parametro:

public void process(String constantExpected){
    ...    
}

Puoi invocarlo in questo modo:

process(MyClass.ONE_CONSTANT);

o

process(MyClass.ANOTHER_CONSTANT);

Ma nessun vincolo di compilazione ti impedisce di invocarlo in questo modo:

process("a not defined constant value");

Avresti l'errore solo in fase di esecuzione e solo se eseguissi un controllo alla volta sul valore trasmesso.

Con enum, i controlli non sono richiesti poiché il client può solo passare un valore enum in un parametro enum.

Ad esempio, qui due valori definiti in una classe enum (così costante e pronta all'uso):

public enum MyEnum {

    ONE_CONSTANT("value"), ANOTHER_CONSTANT(" another value");

    private String value;

    MyEnum(String value) {
       this.value = value;
    }
         ...
}

Ecco un metodo che prevede di avere uno di questi valori enum come parametro:

public void process(MyEnum myEnum){
    ...    
}

Puoi invocarlo in questo modo:

process(MyEnum.ONE_CONSTANT);

o

process(MyEnum.ANOTHER_CONSTANT);

Ma la compilation non ti permetterà mai di invocarla in questo modo:

process("a not defined constant value");

Dove dovremmo dichiarare le costanti?

Se l'applicazione contiene un'unica classe esistente che possiede una coesione funzionale specifica e forte con i valori costanti, 1) e 2) appaiono più intuitivi.
In generale, facilita l'uso delle costanti se queste sono dichiarate nella classe principale che le manipola o che ha un nome molto naturale per indovinare che lo troveremo all'interno.

Ad esempio nella libreria JDK, i valori esponenziali e costanti pi sono dichiarati in una classe che dichiara non solo dichiarazioni costanti ( java.lang.Math).

   public final class Math {
          ...
       public static final double E = 2.7182818284590452354;
       public static final double PI = 3.14159265358979323846;
         ...
   }

I clienti che utilizzano le funzioni matematiche si affidano spesso alla Mathclasse. Quindi, possono trovare costanti abbastanza facilmente e possono anche ricordare dove Ee PIsono definiti in modo molto naturale.

Se la tua applicazione non contiene una classe esistente che ha una coesione funzionale molto specifica e forte con i valori costanti, i modi 1 variante e 2 variante appaiono più intuitivi.
In generale, non facilita l'uso delle costanti se queste sono dichiarate in una classe che le manipola mentre abbiamo anche 3 o 4 altre classi che le manipolano tanto quanto e nessuna di queste classi sembra essere più naturale di altre valori costanti host.
Qui, ha senso definire una classe personalizzata per contenere solo valori costanti.
Ad esempio nella libreria JDK, l' java.util.concurrent.TimeUnitenum non è dichiarato in una classe specifica in quanto non esiste realmente una e una sola classe specifica JDK che appare come la più intuitiva per tenerla:

public enum TimeUnit {
    NANOSECONDS {
      .....
    },
    MICROSECONDS {
      .....
    },
    MILLISECONDS {
      .....
    },
    SECONDS {
      .....
    },
      .....
}      

Molte classi hanno dichiarato in java.util.concurrentuso loro: BlockingQueue, ArrayBlockingQueue<E>, CompletableFuture, ExecutorService, ... e in realtà nessuno di loro sembra più appropriato per tenere l'enum.


1

Una costante, di qualsiasi tipo, può essere dichiarata creando una proprietà immutabile all'interno di una classe (ovvero una variabile membro con il finalmodificatore). In genere vengono forniti anche i modificatori statice public.

public class OfficePrinter {
    public static final String STATE = "Ready";  
}

Esistono numerose applicazioni in cui il valore di una costante indica una selezione da una n-tupla (ad es. Enumerazione ) di scelte. Nel nostro esempio, possiamo scegliere di definire un tipo enumerato che limiterà i possibili valori assegnati (ovvero una maggiore sicurezza del tipo ):

public class OfficePrinter {
    public enum PrinterState { Ready, PCLoadLetter, OutOfToner, Offline };
    public static final PrinterState STATE = PrinterState.Ready;
}

1

Una singola classe di costanti generiche è una cattiva idea. Le costanti dovrebbero essere raggruppate insieme alla classe a cui sono logicamente più correlate.

Piuttosto che usare variabili di qualsiasi tipo (specialmente enumerazioni), suggerirei di usare metodi. Creare un metodo con lo stesso nome della variabile e farlo restituire il valore assegnato alla variabile. Ora elimina la variabile e sostituisci tutti i riferimenti ad essa con le chiamate al metodo appena creato. Se ritieni che la costante sia abbastanza generica da non dover creare un'istanza della classe solo per usarla, allora trasforma il metodo costante in un metodo di classe.


1

FWIW, un valore di timeout in secondi dovrebbe probabilmente essere un'impostazione di configurazione (letta da un file delle proprietà o tramite iniezione come in primavera) e non una costante.


1

Qual è la differenza

1.

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

2.

public class MyGlobalConstants {
    private MyGlobalConstants () {} // Prevents instantiation
    public static final int TIMEOUT_IN_SECS = 25;
}

e usando MyGlobalConstants.TIMEOUT_IN_SECSovunque abbiamo bisogno di questa costante. Penso che entrambi siano uguali.


1
Questo sembra essere essenzialmente un commento in risposta alla risposta fornita da bincob. Penso che si comportino in modo molto simile, ma il punto di bincob era che non definiscono in alcun modo un'interfaccia. E il suggerimento era di aggiungere costanti a classi reali, non di creare una classe di scheletro MyGlobalConstants. (Anche se questo a volte ha senso; usa una "classe statica" avendo costanti statiche e un costruttore privato per prevenire l'istanza; vedi java.lang.math.) Prendi in considerazione l'uso di enum.
Jon Coombs,

Anche l'inserimento di "final" nella dichiarazione di classe impedisce la sottoclasse. (In C # potresti fare "statico", che significa "abstract finale", quindi non c'è bisogno di un costruttore privato esplicito.)
Jon Coombs,

Sì, @JonCoombs ma "final" non impedisce la sua istanza diretta. E Java non consente che sia il final sia il abstract vengano visualizzati insieme per le classi, quindi il costruttore privato che appare all'infinito per impedire sia l'istanza che la sottoclasse. Non ho idea del perché non sia vietato "abstract finale", a parte il fatto che a prima vista sembra contraddittorio nel modo in cui si legge: "non è possibile effettuare la sottoclasse ma questa classe deve essere sottoclassata".

0

Non definirei la classe uguale (a parte l'involucro) della costante ... Avrei almeno una classe di "Impostazioni", "Valori", o "Costanti", dove vivrebbero tutte le costanti. Se ne ho un gran numero, li raggrupperei in classi di costanti logiche (Impostazioni utente, Impostazioni app, ecc.)


Avere una classe chiamata Costanti era ciò che avevo pianificato di fare, che era solo un piccolo esempio che ho trovato.
mk.

0

Per fare un ulteriore passo in avanti, è possibile posizionare le costanti utilizzate a livello globale in un'interfaccia in modo che possano essere utilizzate a livello di sistema. Per esempio

public interface MyGlobalConstants {
    public static final int TIMEOUT_IN_SECS = 25;
}

Ma non implementarlo. Basta fare riferimento a loro direttamente nel codice tramite il nome di classe completo.


Il punto su come dichiararli in un'interfaccia (e non implementarla) è che puoi perdere il "finale statico pubblico".
Tom Hawtin - tackline il

9
Le interfacce servono per definire un contratto comportamentale, non un meccanismo di convenienza per contenere le costanti.
John Topley,

@JohnTopley Sì, ma funziona. ;)
trusktr

0

Per Costanti, Enum è una scelta migliore IMHO. Ecco un esempio

classe pubblica myClass {

public enum myEnum {
    Option1("String1", 2), 
    Option2("String2", 2) 
    ;
    String str;
            int i;

            myEnum(String str1, int i1) { this.str = str1 ; this.i1 = i }


}

0

Uno dei modi in cui lo faccio è creando una classe 'Global' con i valori delle costanti ed eseguendo un'importazione statica nelle classi che necessitano dell'accesso alla costante.


0

static finalè la mia preferenza, userei un solo enumse l'articolo fosse davvero enumerabile.


0

Uso static finalper dichiarare le costanti e seguire la notazione di denominazione ALL_CAPS. Ho visto alcuni esempi di vita reale in cui tutte le costanti sono raggruppate in un'interfaccia. Alcuni post hanno giustamente definito una cattiva pratica, principalmente perché non è a questo che serve un'interfaccia. Un'interfaccia dovrebbe far rispettare un contratto e non dovrebbe essere un luogo in cui inserire costanti non correlate. Anche metterlo insieme in una classe che non può essere istanziato (tramite un costruttore privato) va bene se la semantica costante non appartiene a una classe specifica ( es). Ho sempre inserito una costante nella classe a cui è maggiormente legata, perché ha senso ed è anche facilmente gestibile.

Gli enum sono una buona scelta per rappresentare un intervallo di valori, ma se si memorizzano costanti autonome con un'enfasi sul valore assoluto (es. TIMEOUT = 100 ms) si può semplicemente optare per l' static finalapproccio.


0

Sono d'accordo con quello che molti dicono, è meglio usare enum quando si ha a che fare con una raccolta di costanti. Tuttavia, se stai programmando in Android c'è una soluzione migliore: IntDef Annotation .

@Retention(SOURCE)
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST,NAVIGATION_MODE_TABS})
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
...
public abstract void setNavigationMode(@NavigationMode int mode);
@NavigationMode
public abstract int getNavigationMode();

L'annotazione IntDef è superiore alle enumerazioni in un modo semplice, occupa molto meno spazio in quanto è semplicemente un indicatore di tempo di compilazione. Non è una classe, né ha la proprietà di conversione stringa automatica.


Mentre sono d'accordo con la migliore pratica di non utilizzare l'interfaccia in Java da solo ed evitare enum in Android, questa sostituzione in Android funziona solo quando si utilizza un numero limitato di campi. È un notevole risparmio di memoria, ma può portare a gonfiarsi poiché si è interfacciati per campo in un enum misto. Ad esempio, se ho un enum misto che definisce ciò che un oggetto prende nel suo costruttore, non posso salvare nulla con questo approccio, e sono tornato a costanti non di tipo sicuro perché in Android, non vuoi troppe periodi di classi / interfacce.
Droid Teahouse,

0

È cattiva abitudine e terribile pratica fastidiosa citare Joshua Bloch senza capire il fondamentalismo fondamentale zero.

Nemmeno io ho letto nulla di Joshua Bloch

  • è un programmatore terribile
  • o le persone finora che trovo citandolo (Joshua è il nome di un ragazzo presumo) stanno semplicemente usando il suo materiale come script religiosi per giustificare le loro indulgenze religiose sul software.

Come nel fondamentalismo biblico si possono riassumere tutte le leggi bibliche

  • Ama l'identità fondamentale con tutto il tuo cuore e tutta la tua mente
  • Ama il tuo prossimo come te stesso

e così allo stesso modo il fondamentalismo dell'ingegneria del software può essere riassunto da

  • dedicarti ai fondamentali zero-terra con tutta la tua potenza e la tua mente di programmazione
  • e dedica all'eccellenza dei tuoi colleghi programmatori come faresti per te stesso.

Inoltre, tra i circoli fondamentalisti biblici viene disegnato un corollario forte e ragionevole

  • Prima Ama te stesso. Perché se non ami te stesso molto, allora il concetto di "ama il tuo prossimo come te stesso" non ha molto peso, poiché "quanto ami te stesso" è la linea di riferimento sopra la quale ameresti gli altri.

Allo stesso modo, se non ti rispetti come programmatore e accetti semplicemente le dichiarazioni e le profezie di alcuni guru-nath programmatori SENZA mettere in discussione i fondamenti, le tue citazioni e l'affidamento a Joshua Bloch (e simili) non ha senso. E quindi, in realtà non avresti rispetto per i tuoi colleghi programmatori.

Le leggi fondamentali della programmazione software

  • la pigrizia è la virtù di un buon programmatore
  • devi rendere la tua vita di programmazione più semplice, pigra e quindi il più efficace possibile
  • devi rendere le conseguenze e le viscere della tua programmazione il più semplice, il più pigro e quindi il più efficace possibile per i tuoi programmatori vicini che lavorano con te e raccolgono le tue viscere di programmazione.

Le costanti del modello di interfaccia sono una cattiva abitudine ???

In quali leggi della programmazione fondamentalmente efficace e responsabile rientra questo editto religioso?

Basta leggere l'articolo di Wikipedia sulle costanti del modello di interfaccia ( https://en.wikipedia.org/wiki/Constant_interface ), e le sciocche scuse che afferma contro le costanti del modello di interfaccia.

  • Whatif-No IDE? Chi mai come programmatore software non userebbe un IDE? Molti di noi sono programmatori che preferiscono non dover dimostrare di avere un realismo macho aescetico evitando l'uso di un IDE.

    • Inoltre, attendi un secondo sostenitore della programmazione micro-funzionale come mezzo per non aver bisogno di un IDE. Aspetta di leggere la mia spiegazione sulla normalizzazione del modello di dati.
  • Inquina lo spazio dei nomi con variabili non utilizzate nell'ambito corrente? Potrebbero essere i sostenitori di questa opinione

    • non sono a conoscenza della necessità e della necessità di normalizzare il modello di dati
  • L'uso delle interfacce per far rispettare le costanti è un abuso di interfacce. I sostenitori di tale hanno una cattiva abitudine di

    • non vedendo che le "costanti" devono essere trattate come un contratto. E le interfacce vengono utilizzate per far rispettare o proiettare la conformità a un contratto.
  • È difficile se non impossibile convertire le interfacce in classi implementate in futuro. Hah .... hmmm ... ???

    • Perché vorresti impegnarti in un modello di programmazione come il tuo sostentamento permanente? IOW, perché dedicarti a una tale AMBIVALENTE e cattiva abitudine di programmazione?

Qualunque siano le scuse, NON vi è alcuna SCUSA VALIDA quando si tratta di ingegneria software FONDAMENTALMENTE EFFICACE per delegittimare o in generale scoraggiare l'uso di costanti di interfaccia.

Non importa quali fossero gli intenti e gli stati mentali originali dei padri fondatori che hanno elaborato la Costituzione degli Stati Uniti. Potremmo discutere degli intenti originali dei padri fondatori, ma tutto ciò che mi interessa sono le dichiarazioni scritte della Costituzione degli Stati Uniti. Ed è responsabilità di ogni cittadino americano sfruttare il fondamentalismo letterario scritto, non gli intenti fondativi non scritti, della Costituzione degli Stati Uniti.

Allo stesso modo, non mi interessa quali fossero gli intenti "originali" dei fondatori della piattaforma Java e del linguaggio di programmazione per l'interfaccia. Quello che mi interessa sono le funzionalità efficaci fornite dalla specifica Java e intendo sfruttare al massimo quelle funzionalità per aiutarmi a soddisfare le leggi fondamentali della programmazione software responsabile. Non mi interessa se sono percepito come "violare l'intenzione di interfacce". Non mi importa cosa dice Gosling o qualcuno di Bloch del "modo corretto di usare Java", a meno che ciò che dicono non violi il mio bisogno di EFFICACE fondamenti soddisfacenti.

Fondamentale è la normalizzazione del modello di dati

Non importa come il tuo modello di dati sia ospitato o trasmesso. Se si utilizzano interfacce o enum o whatevernots, relazionali o no-SQL, se non si capisce la necessità e il processo di normalizzazione del modello di dati.

Dobbiamo innanzitutto definire e normalizzare il modello di dati di un insieme di processi. E quando abbiamo un modello di dati coerente, SOLO allora possiamo usare il flusso di processo dei suoi componenti per definire il comportamento funzionale e il processo blocca un campo o un regno di applicazioni. E solo allora possiamo definire l'API di ciascun processo funzionale.

Anche le sfaccettature della normalizzazione dei dati, come proposto da EF Codd, sono ora messe a dura prova e messe a dura prova. ad esempio, la sua affermazione su 1NF è stata criticata come ambigua, disallineata e troppo semplificata, così come il resto delle sue dichiarazioni soprattutto nell'avvento dei moderni servizi di dati, tecnologia repo e trasmissione. IMO, le dichiarazioni EF Codd dovrebbero essere completamente abbandonate e dovrebbe essere progettata una nuova serie di dichiarazioni più matematicamente plausibili.

Un evidente difetto di EF Codd e la causa del suo disallineamento per un'efficace comprensione umana è la sua convinzione che i dati multidimensionali e mutabili di dimensione umana percepibili possano essere percepiti in modo efficiente attraverso una serie di mappature bidimensionali frammentarie.

I fondamenti della normalizzazione dei dati

Cosa non ha potuto esprimere EF Codd.

All'interno di ciascun modello di dati coerente, si tratta dell'ordine sequenziale graduale di coerenza del modello di dati da raggiungere.

  1. Unità e identità delle istanze di dati.
    • progettare la granularità di ciascun componente di dati, per cui la loro granularità è a un livello in cui ogni istanza di un componente può essere identificata e recuperata in modo univoco.
    • assenza di aliasing di istanza. cioè, non esiste alcun mezzo per cui un'identificazione produce più di un'istanza di un componente.
  2. Assenza di diafonia di istanza. Non esiste la necessità di utilizzare una o più altre istanze di un componente per contribuire a identificare un'istanza di un componente.
  3. L'unità e l'identità delle componenti / dimensioni dei dati.
    • Presenza di de-aliasing dei componenti. Deve esistere una definizione per cui un componente / dimensione può essere identificato in modo univoco. Qual è la definizione principale di un componente;
    • laddove la definizione primaria non comporti l'esposizione di sottodimensionamenti o componenti di componenti che non fanno parte di un componente previsto;
  4. Mezzi unici di dealiasing dei componenti. Deve esistere una e una sola definizione di de-aliasing di un componente per un componente.
  5. Esiste una e una sola interfaccia di definizione o contratto per identificare un componente padre in una relazione gerarchica di componenti.
  6. Assenza di diafonia dei componenti. Non esiste la necessità di utilizzare un membro di un altro componente per contribuire all'identificazione definitiva di un componente.
    • In tale relazione genitore-figlio, la definizione identificativa di un genitore non deve dipendere da parte dell'insieme di componenti membri di un figlio. Un componente membro dell'identità di un genitore deve essere l'identità figlio completa senza ricorrere al riferimento a uno o tutti i figli di un figlio.
  7. Aspetti bi-modali o multimodali preventivi di un modello di dati.
    • Quando esistono due definizioni candidate di un componente, è evidente che esistono due diversi modelli di dati confusi come uno. Ciò significa che c'è incoerenza a livello di modello di dati o a livello di campo.
    • Un campo di applicazioni deve utilizzare in modo coerente un solo modello di dati.
  8. Rileva e identifica la mutazione del componente. A meno che non sia stata eseguita un'analisi statistica dei componenti di enormi dati, probabilmente non si vede o non si vede la necessità di trattare la mutazione dei componenti.
    • Un modello di dati può far mutare ciclicamente o gradualmente i suoi componenti.
    • La modalità può essere rotazione membro o rotazione trasposizione.
    • La mutazione a rotazione dei membri potrebbe essere lo scambio distinto di componenti figlio tra componenti. O dove dovrebbero essere definiti componenti completamente nuovi.
    • La mutazione trasposizionale si manifesterebbe come un membro dimensionale che muta in un attributo, viceversa.
    • Ogni ciclo di mutazione deve essere identificato come un dato modale distinto.
  9. Versionize ogni mutazione. Tale che è possibile estrarre una versione precedente del modello di dati, quando forse sorge la necessità di trattare una mutazione di 8 anni del modello di dati.

In un campo o in una griglia di applicazioni componenti inter-servicing, ci deve essere un solo modello di dati coerente o esiste un mezzo per un modello di dati / versione per identificarsi.

Stiamo ancora chiedendo se potremmo usare le Costanti di interfaccia? Veramente ?

Sono in gioco problemi di normalizzazione dei dati più consequenziali di questa domanda banale. Se non risolvi questi problemi, la confusione che pensi che le costanti dell'interfaccia causino non è relativamente nulla. Zilch.

Dalla normalizzazione del modello di dati quindi si determinano i componenti come variabili, come proprietà, come costanti dell'interfaccia del contratto.

Quindi si determina quale va in iniezione di valore, segnaposto di configurazione della proprietà, interfacce, stringhe finali, ecc.

Se devi usare la scusa della necessità di individuare un componente più facile da dettare contro le costanti dell'interfaccia, significa che hai la cattiva abitudine di non praticare la normalizzazione del modello di dati.

Forse desideri compilare il modello di dati in una versione di vcs. Che è possibile estrarre una versione distintamente identificabile di un modello di dati.

I valori definiti nelle interfacce sono completamente sicuri di non essere mutabili. E condivisibile. Perché caricare un set di stringhe finali nella tua classe da un'altra classe quando tutto ciò di cui hai bisogno è quel set di costanti ??

Quindi perché non pubblicare questo contratto per un modello di dati? Voglio dire se riesci a gestirlo e normalizzarlo in modo coerente, perché no? ...

public interface CustomerService {
  public interface Label{
    char AssignmentCharacter = ':';
    public interface Address{
      String Street = "Street";
      String Unit= "Unit/Suite";
      String Municipal = "City";
      String County = "County";
      String Provincial = "State";
      String PostalCode = "Zip"
    }

    public interface Person {
      public interface NameParts{
        String Given = "First/Given name"
        String Auxiliary = "Middle initial"
        String Family = "Last name"
      }
    }
  }
}

Ora posso fare riferimento alle etichette contratte delle mie app in un modo come

CustomerService.Label.Address.Street
CustomerService.Label.Person.NameParts.Family

Questo confonde il contenuto del file jar? Come programmatore Java non mi interessa la struttura del vaso.

Ciò presenta complessità allo scambio di runtime motivato da osgi? Osgi è un mezzo estremamente efficiente per consentire ai programmatori di continuare nelle loro cattive abitudini. Ci sono alternative migliori di osgi.

O perché no? Non vi è alcuna perdita di Costanti private nel contratto pubblicato. Tutte le costanti private devono essere raggruppate in un'interfaccia privata denominata "Costanti", perché non voglio cercare costanti e sono troppo pigro per digitare ripetutamente "stringa finale privata".

public class PurchaseRequest {
  private interface Constants{
    String INTERESTINGName = "Interesting Name";
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

Forse anche questo:

public interface PurchaseOrderConstants {
  public interface Properties{
    default String InterestingName(){
       return something();
    }
    String OFFICIALLanguage = "Official Language"
    int MAXNames = 9;
  }
}

L'unico problema con le costanti dell'interfaccia che vale la pena considerare è quando l'interfaccia è implementata.

Questa non è "l'intenzione originale" delle interfacce? Come se mi interessasse "l'intenzione originale" dei padri fondatori nell'elaborare la Costituzione degli Stati Uniti, piuttosto che il modo in cui la Corte Suprema avrebbe interpretato le lettere scritte della Costituzione degli Stati Uniti ???

Dopotutto, vivo nella terra dei liberi, dei selvaggi e dei coraggiosi. Sii coraggioso, sii libero, sii selvaggio - usa l'interfaccia. Se i miei colleghi programmatori si rifiutano di usare mezzi di programmazione efficienti e pigri, sono obbligato dalla regola d'oro a ridurre la mia efficienza di programmazione per allinearli con i loro? Forse dovrei, ma questa non è una situazione ideale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.