Where to define constants in Java that are used in several unrelated classes

The question of where to define constants in Java has repeatedly appeared on the forums, but I'm struggling to solve a problem that makes me comfortable.

To make it simple, suppose I have two classes: WriteMyData and ReadMyData . None of them are subclasses of the other. Both classes have two constants that are vital to their work: String DELIMITER and int LENGTH . In the future, I might want to change the meaning of these constants so that they are defined somewhere suitable.

Consensus often favors the enum type. However, in my case, there is nothing to list, so in the end I have only one element in enum , which I call DEFAULT :

 public enum DataSettings { DEFAULT(",", 32); private final String delimiter; private final int length; DataSettings(String delmiter, int length) { this.delimiter = delimiter; this.length = length; } public String getDelimiter() { return delimiter; } public int getLength() { return length; } } 

Thus, in both my classes, I access the constants through DataSettings.DEFAULT.getDelimiter() and DataSettings.DEFAULT.getLength() .

Is this a really good OO style? Is enum overkill possible? If I do not use enum , what should I do instead? Creating an interface for constants seems to be underestimated, and there seems to be no natural superclass for my classes. Is a beginner's error having only one default element in enum ?

+7
java enums constants
source share
8 answers

Just create something like the Constants.java class, where you put all the constants.

For example:

 public class Constants { public static final String DELIMITER = "-"; public static final int LENGTH = 1; } 

And use them wherever you want:

 Constants.DELIMITER Constants.LENGTH 
+3
source share

If only these two constants do not have more than this, you may have an interface like

 interface DataSetting { String DELIMITER = ","; int LENGTH = 32; } 

And if you need to initialize through a property

 public class DataSetting { public static String DELIMITER = ","; public static int LENGTH = 32; static { DELIMITER = System.getProperty("delimiter"); LENGTH = Integer.parseInt(System.getProperty("length")); // or from config } } 
+2
source share

Using enum when there is nothing to list is really bad practice.

Another alternative mentioned using interface is also a poor choice. Effective Java, clause 19 best describes it:

Item19: Use Interfaces for Type Definition Only

When a class implements an interface, the interface serves as a type that can be used to refer to instances of the class. That a class implements an interface should therefore say something about what the client can do with instances of the class. Incorrectly defined interface for any other purpose.

One type of interface that failed this test is the so-called persistent interface. Such an interface does not contain methods; it consists solely of static finite fields, each of which exports a constant. Classes using these constants implement the interface to avoid the need to define constant names with the class name.

The correct implementation is to define an uninteresting utility class:

 public class Constants { private Constants(){} // Private constructor prevents instantiation AND subclassing public static final String DELIMITER = "-"; public static final int LENGTH = 1; } 

For convenience, you can statically import constants into your code:

 import static com.example.Constants.*; public class Test { public static void main(String[] args){ System.out.println(DELIMITER); // prints "-" } } 
+1
source share

Enumeration with only one value may not make much sense, although it may be useful if you plan to distribute any values ​​that may contain.

An alternative to what you are saying would be the following:

  • You have an open class that provides project-specific constants. You can force this class to load its values ​​from some configuration file when your application starts, so you can control the values ​​of these constants.

  • You have a separate set of methods, a suffix with WithDefaultValues for your read and write methods. These methods, in turn, will call your other methods and pass default parameters.

As a side note, it might make sense to simply overload the methods that you already have so that you have an implementation that defaults to these constants. If so, be sure to write this in your method signature.

0
source share

IMO, Enum is redundant in this case. Enums are made for listings.

For global constants, you can simply create a public static attribute of the final class in a java class or java interface, although the latter is not the usual approach (see Interfaces with static fields in java for exchanging "constants" )

0
source share

I would suggest another solution that does not use constants in WriteMyData and ReadMyData .

Pass separator and length as constructor parameters. That way you can unit test these classes with parameters that can facilitate testing.

When it is important that each instance uses the same values ​​for the separator and length, both must be created in the same place and available for use by clients. The location where the instances are created is a good place to have constants for delimiter and length values.

0
source share

You can create an interface.
By default, constants in the interface are static and final.
And you can use this variable through the reference interface.

 public interface AnyNameInterface { String AnyVar ="DEMO"; Double AnyVar_2 = 123.00; } 

Use as:

 AnyNameInterface.AnyVar AnyNameInterface.AnyVar_2 
0
source share

I would like to add that even when there is something to enumerate, enums can not always be used as a container for constants, even if they are good.

For example, javax.ws.rs.Path defines a single annotation type element of type String. However, this does not compile:

@Path(MyEnum.BASE_PATH) nor @Path(MyEnum.BASE_PATH.name())

In addition, in cases where it is impossible to define constants in the class itself or on some ordinary superclass, a discussion often appears between the definition of constants in the vs class in the interface. A third option would be to define them in an annotation.

 public @interface MyAnnotation { String QUESTIONS = "/questions"; String ANSWERS = "/answers"; } 

An annotation approach avoids the "persistent interface" trap. In my opinion, this error lies in the fact that the interface as a permanent container is a bad idea in itself - the problem is that the callers decide to implement the interface and not access the constants through, for example. static import.

0
source share

All Articles