1

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?

jeff
  • 3,618
  • 9
  • 48
  • 101
  • 2
    That doesn't seem like the correct use of enums to me. You don't gain any benefits over `public static final` fields, and it makes your code more verbose. – resueman Jan 12 '16 at 19:22
  • 1
    Yes, because the primary goal of enums is to provide a set of distinctly named, distinctly typed values rather than a way to name a bunch of BigDecimals. Your initial approach was sensible for your use, you can make a class with your constants and then use them wherever needed. You can use static imports to keep things short. – pvg Jan 12 '16 at 19:25
  • yeah, I felt something wasn't right with my Enum approach. But this http://stackoverflow.com/a/66228/358794 post and a few other places was making me think I shouldn't use a constants class. – jeff Jan 12 '16 at 19:33
  • @jeff the objections there are partially over the type of thing being stored in a constant vs an enum. I've expanded on this in an answer below. You don't want enums for your use, constants will do and you can easily put them more or less wherever you like – pvg Jan 12 '16 at 19:43
  • If these constants are correlated it's ok to have an Enum to encapsulate them. And having an extra attribute of type string is also fine, I use this pattern a lot. – Lluis Martinez Jan 30 '19 at 12:22

4 Answers4

1

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.

scottb
  • 9,908
  • 3
  • 40
  • 56
  • Why does this post http://stackoverflow.com/questions/66066/what-is-the-best-way-to-implement-constants-in-java suggest not creating static final constants in a separate class and seem to favor of Enum? – jeff Jan 12 '16 at 19:49
  • I think my advice lines up with that post, with the exception of defining a separate class. The general gist is use an enum when feasible (it isn't always). If the constants are generally useful to many projects or are thematically related, use a constant class. This is the advice given by Joshua Bloch in "Effective Java, 2nd Ed." If constants are used in a single project, it is still better to use a constant class over a constant interface if others will be maintaining your code at some point. Constants defined in a regular class is fine as well. – scottb Jan 12 '16 at 20:26
1

You want to use a constant when you want readability and convenience, so for instance

static final double PI = 3.1415;

lets you write something like

c = 2 * PI * r;

making the intent clear. An enum is useful when you want to ensure your values are from a pre-defined set and the check to be done at compile time. Suppose I wanted write a class modeling something like a traffic light. I can define an enum for its states, STOP, CAUTION and GO. That way, I can ensure at compile time, that any setting of the state of my light would be one of these three states. If I defined integer constants for these, there is nothing stopping someone from not using my constants and simply setting the state to 139.

The ability to associate values with my Enum elements is an additional convenience, in my traffic light case, I could associate an RGB value with each for display purposes, for instance.

In your case, it seems reasonably clear constants will do and enums just complicate your code.

pvg
  • 2,673
  • 4
  • 17
  • 31
  • Yes I like the constant approach too and it made sense when I only had one class that was using the constants. I was struggling with declaring them in a separate class based on some of the responses over here http://stackoverflow.com/questions/66066/what-is-the-best-way-to-implement-constants-in-java. I see your comment above on my Q about that posts in that URL and feel comfortable now that constants in a separate class are the way to go. – jeff Jan 12 '16 at 20:00
0

Seems like the enum would give you ability to move the key value pairs out to another structure which cleans up the class that utilizes this composition. This can also be achieved by creating a class that has public properties like BD_0_00... Enum really doesn't buy you much over that implementation.

bhiku
  • 81
  • 2
-1

Would not use enum in this case, unless there is more data comming down the road describing the values.

A prefered way of doing things would be to make them global, I.E. public static final. Since BigDecimal is immutable, you do not have to worry about the general "no global state" rule. They basically become constants.

Erik Nyström
  • 537
  • 4
  • 9