Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to define constants in Java that are used in a couple of unrelated classes

The question of where to define constants in Java has appeared numerous times in forums, yet I am struggling to settle on a solution I feel comfortable with.

To make it simple, suppose I have two classes: WriteMyData and ReadMyData. None is a subclass of the other. Both classes share two constants that are vital for their operation: String DELIMITER and int LENGTH. In the future I might want to change the value of these constants so they should be defined somewhere appropriate.

The consensus seems to often favour the enum type. However, there is nothing to enumerate in my case, so I end up with only one item in my 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 really good OO style? Is the use of enum perhaps overkill? If I do not use enum, what should I do instead? Creating an interface for constants seems to be frowned upon, and there seems to be no natural superclass for my classes to derive from. Is it a beginners mistake to have only one default item in an enum?

like image 303
DustByte Avatar asked Jan 07 '16 11:01

DustByte


3 Answers

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

For example:

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

And use them where you want by:

Constants.DELIMITER
Constants.LENGTH
like image 117
antoniodvr Avatar answered Oct 27 '22 08:10

antoniodvr


If only those two constans and not going to have more than that, You can have a Interface like

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

And if you need to initilize through 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 
  }
}
like image 25
vels4j Avatar answered Oct 27 '22 06:10

vels4j


Using an enum when there is nothing to enumerate is indeed bad practice.

The other mentioned alternative, using an interface is also a poor choice. Effective Java, Item 19 describes it best:

Item19: Use interfaces only to define types

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 a client can do with instances of the class. It is inappropriate to define an interface for any other purpose.

One kind of interface that fails this test is the so-called constant interface. Such an interface contains no methods; it consists solely of static final fields, each exporting a constant. Classes using these constants implement the interface to avoid the need to qualify constant names with a class name.

The correct implementation is to define a non-instantiable 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 the constants in your code:

import static com.example.Constants.*;

public class Test {
    public static void main(String[] args){
        System.out.println(DELIMITER); // prints "-"
    }
}
like image 39
rinde Avatar answered Oct 27 '22 06:10

rinde