Search code examples
javaconstantsbigdecimal

Using Java Enum for BigDecimal Constants


Originally I had one class with a bunch of private static finals

private static final BigDecimal BD_0_06 = new BigDecimal("0.06");
private static final BigDecimal BD_0_08 = new BigDecimal("0.08");
private static final BigDecimal BD_0_10 = new BigDecimal("0.10");
private static final BigDecimal BD_0_12 = new BigDecimal("0.12");
private static final BigDecimal BD_0_14 = new BigDecimal("0.14");
    ...

and a bunch of methods in that class that used those constants

private void computeFastenerLengthToleranceMax() {
        if (nominal_fastener_length.compareTo(BigDecimal.ONE) > 0 && nominal_fastener_length.compareTo(BD_TWO_AND_ONE_HALF) <= 0) {
            if (spec.getBasic_major_diameter().compareTo(BD_ONE_QUARTER) >= 0 && spec.getBasic_major_diameter().compareTo(BD_THREE_EIGTHS) <= 0) {
                setLength_tolerance_max(BD_0_02);
            }
            if (spec.getBasic_major_diameter().compareTo(BD_SEVEN_SIXTEENTHS) >= 0 && spec.getBasic_major_diameter().compareTo(BD_ONE_HALF) <= 0) {
                setLength_tolerance_max(BD_0_04);
            }
            if (spec.getBasic_major_diameter().compareTo(BD_NINE_SIXTEENTHS) >= 0 && spec.getBasic_major_diameter().compareTo(BD_THREE_QUARTER) <= 0) {
                setLength_tolerance_max(BD_0_06);
            }

Now I'd like to create other similar classes that use the same constants. At first I extended a based class that contained these constants but then decided to try composition instead of inheritance because of other issues and now I'm trying to use Enum for my constants.

public enum EnumBD {
BD_0_00 (new BigDecimal("0.00")),
BD_0_02 (new BigDecimal("0.02")),
BD_0_03 (new BigDecimal("0.03")),
BD_0_04 (new BigDecimal("0.04")),
BD_0_05 (new BigDecimal("0.05")),
    .....
private BigDecimal value;

private EnumBD(BigDecimal value) {
    this.value = value;
}

public BigDecimal getValue() {
    return value;
}

}

But in my method my reference to all my constants goes from something like this

setLength_tolerance_max(BD_0_02);

to this

setLength_tolerance_max(EnumBD.BD_0_02.getValue());

Am I off track or is this how Enum constants were intended to be used?


Solution

  • Now I'd like to create other similar classes that use the same constants. At first I extended a based class that contained these constants but then decided to try composition instead of inheritance because of other issues and now I'm trying to use Enum for my constants.

    There are basically two ways (aside from defining your own enum class), broadly speaking, to export constants for use in multiple classes. That said, you really ought to consider whether there is a workable way to use an enum class to represent your constants since an enum class is the facility of choice to use whenever you have a set of fixed constants that are known at compile time. The following is for a case in which you have decided not to use an enum class.

    • Use an interface

    This advice is provided with reservation. This mechanism works as a means to export constants, but it is regarded by coding experts as an antipattern and not one to be emulated, most especially in an API that you exporting.

    Nevertheless it is true that if you define static final constants in an interface, any class that implements that interface (and any subclass of that class) will be able to use your constants by their unqualified names. An interface that defines ONLY constants in this way is called a constant interface. There are a few examples of constant interfaces in the Java Platform Libraries.

    The reasons not to use constant interfaces are many and have been discussed elsewhere ... however they can be convenient to use. Use constant interfaces at your own prerogative and be aware that they have some potential to cause problems (namespace pollution, programmer confusion, etc).

    • Use a class

    Define your constants as public, final, and static in an ordinary class. They should very likely also be primitive or immutable types. Your class can then export these constants to any other class that can make use of them.

    This is preferred over exporting constants with a constant interface because interfaces should really only be used to define types and APIs. Non-instantiable "constant classes" are a perfectly acceptable use of the class mechanism. This is especially true if the constants are thematically related. For example, say you wish to define constants representing various boiling points:

    public class BoilingPoints {
        public static final double WATER = 100.0;
        :
        :
        public static final double ETHANOL = 86.2;
    
        private BoilingPoints() { throw new AssertionError(); }
    }
    

    Note that the constructor assures that the class is non-instantiable.

    The main downside is that you ordinarily must qualify constants exported from a class with the class name. Since the static import mechanism was added to the language, you don't -have- to do that if you don't wish to.