2

I had the following field in my code:

private static final int NUM_NANOSECONDS_IN_MILLISECOND = 1000000;

I was told that I should be using an enum for this for type safety. This is not something I am familiar with. But if this is the case, I don't know when it would ever be appropriate to use the final keyword on a field.

When should I use the final keyword instead of enums?

Evorlor
  • 7,263
  • 17
  • 70
  • 141
  • This case is not necessarily for `enum`, but the decision between using an `int` and an `enum` is by design. I would suggest implementing this the simplest and more readable way you find it. If this, later, evolves and needs to be changed, change it then, not now. – Luiggi Mendoza Apr 06 '15 at 15:00
  • 4
    Why would an enum even make sense in this context? You've got literally one value, not several. It'd also depend on the usage; if you're adding values to it on-the-fly, then you may consider adding more constants before an enum. – Makoto Apr 06 '15 at 15:00
  • 3
    Who told you this? Whoever it was, ask them for an explanation and edit your question with the explanation, because I don't know what the heck they're talking about either. It sounds like a comment more appropriate for C/C++. – ajb Apr 06 '15 at 15:01
  • 1
    If you're using Java 1.4, there are no enums. Otherwise, enums usually are a better choice. Although for numerical constants like this case, a `final int` is more reasonable. – EpicPandaForce Apr 06 '15 at 15:01
  • @ajb he probably means that people used to use `public static final int` in place of `enum`s, back when `enum`s did not exist. Now, there are still cases where numerical constants make more sense than enums, but also cases where using numerical constants to represent enumerations is just not type-safe. – EpicPandaForce Apr 06 '15 at 15:02
  • 2
    @EpicPandaForce Ah, so the person who gave him that advice didn't bother to actually read his code, or think about it. Instead he saw `private static final int` and responded like one of Pavlov's dogs. Wonderful. – ajb Apr 06 '15 at 15:04
  • 3
    I'm wondering how this person would react on https://docs.oracle.com/javase/8/docs/api/constant-values.html... – Pshemo Apr 06 '15 at 15:08
  • 1
    @Pshemo agh, the horrors of Pre-1.5 code! – EpicPandaForce Apr 06 '15 at 15:14
  • Probably one of simplest way to put it is: use constant fields if *value* is most important like `Integer.MAX_VALUE`, use enum if what is important is *variable* (like its name, value doesn't matter that much as long as it is different from other constants) `if (accessLevel == Levels.GOD)`. – Pshemo Apr 06 '15 at 15:18

5 Answers5

6

Using an enum avoids using an int, not final. Using a dedicated enum provides type safety, so you can have clearer method signatures and avoid bugs. final is used to prevent changing a value once set, and is a generally good practice regardless of the variable's type.

In this case however I'm not sure what value an enum gives you. NUM_NANOSECONDS_IN_MILLISECOND doesn't seem like it should be a dedicated type, and as @BoristheSpider suggests, you shouldn't need this field at all. Perhaps your associate was suggesting using an enum for the unit (e.g. NANOSECOND, MILLISECOND, etc) rather than storing ratios like this. In that case, the existing TimeUnit enum is definitely your friend.

dimo414
  • 47,227
  • 18
  • 148
  • 244
6

Constants are just that, constants with a name. Enums are literal constants that have a value. I explain...

Consider:

public final static int NORTH = 0;
public final static int SOUTH = 1;
public final static int EAST = 2;
public final static int WEST = 3;

and

public enum Direction {
    NORTH, SOUTH, EAST, WEST
}

From a readability standpoint it kinda looks the same:

if(direction == NORTH)

or with enums:

if(direction == Direction.NORTH)

Where things might go wrong is that with the final constant, you can also do

if(direction == 0)

Now it's more difficult to understand the code even though it does the same thing. With enums, you just can't do that so it's let problems.

Similarly, when expecting a direction as a method argument:

with final static:

public void myMethod(int direction)

and with enums:

public void myMethod(Direction direction)

It's clearer, and less opportunities for problems.

This is just a beginning. Enums can actually have methods that help you better manage the information they contain. Read up here for a clean explanation.

Example:

public enum Direction {
    NORTH (0, 1),
    SOUTH (0, -1),
    EAST (1, 0),
    WEST (-1, 0)

    private int xDirection, yDirection;

    Direction(int x, int y) {
        this.xDirection = x;
        this.yDirection = y;
    }

    public Vector2D getTranslation() {
        return new Vector2D(this.xDirection, this.yDirection);
    }
}

So then in your code:

public void moveThePlayer(Player p, Direction d) {
    p.translate(d.getTranslation());
}

moveThePlayer(p, Direction.NORTH);

This becomes really hard to do with final static. Or at least, it gets very unreadable.

All this being said, with the particular case you are working with there, if there's only one numeric constant value, I'd keep the final static. No point using an enum if there's a single value.

marcolopes
  • 9,232
  • 14
  • 54
  • 65
mprivat
  • 21,582
  • 4
  • 54
  • 64
4

It honestly depends on what you need. enum as its name shows stands for enumeration.

Enumerations have multiple elements like so

public enum Colors {
    CYAN, MAGENTA, YELLOW, BLACK
}

You could even give them numerical values or so! Because enums are cool.

public enum RGBColors {
    RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF);

    private int hexacolor;

    private RGBColors(int hexacolor) {
        this.hexacolor = hexacolor;
    }

    public int getColorValue() {
        return hexacolor;
    }
}

Your case is just a numerical constant. A single numerical constant.

public static final long SUCH_NUMERICAL_VALUE = 12367160L;

This is just a constant. This is not an enumeration. There is also no reason for it to be an enumeration, as you are just using it as a number.

The biggest advantage (in my opinion) of an enum is that you can iterate on every element of its type.

for(RGBColors rgbColor : RGBColors.values()) {
    ... //do things with rgbColor for each of them
}

You cannot do that with public static final int. I even wrote an enum wrapper around a bunch of public static final properties here because of this problem: https://stackoverflow.com/a/28295134/2413303

More importantly, you can easily read what value stands for what without having to go deep into the source:

RGBColors red = RGBColors.RED;

Now let's see this with int:

int red = RGBColors.RED;

I could just say

int red = 0; //red color

Who will tell what on earth that is later? Who knows!

Anyways, the short answer is, enums are great when you're specifying enumerations, aka multiple elements (or you're creating enum singletons), and these elements need to have extra methods or properties.

public enum MySingleton { //this is an enum singleton
    INSTANCE;

    public void doThings() {
        System.out.println("hello!");
    }
}

MySingleton.INSTANCE.doThings(); //hello!

Constants (public static final) are great when you use them as exactly that: constants.

Community
  • 1
  • 1
EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428
3

I would say that the general use case for enums would be when you have a small finite set of values that form some set you are modeling and you are going to enumerate each one. They can also help ensure that a field that should contain one of these values does not contain some other value.

In this case, neither seems to apply. You could just as well have NUM_NANOSECONDS_IN_MICROSECOND, NUM_NANOSECONDS_IN_SECOND, NUM_NANOSECONDS_IN_PI_MILLISECONDS, and so on, and you aren't going to enumerate each one. Furthermore, it would seem that the variables you are going to be storing these values in probably shouldn't be restricted to the values of the defined constants.

Samuel Edwin Ward
  • 6,526
  • 3
  • 34
  • 62
1

When writing source code it is best to rely on the compiler as much as possible to help you find logic errors. One way is to use variable and constant types so that if you use the wrong constant for a method, the compiler will flag this as an error.

The advice is not really about using final versus enum since those are really two different programming concepts. It is instead using an enum to create an explicit and unique type versus using an int which is much less explicit and unique. If you use int as part of the method signature for a function that is supposed to take nanoseconds then any int value will be accepted by the compiler. If you instead use an enum then only those values that are specified in the enum are allowed. Using anything else will cause the compiler to issue an error.

The final keyword is a way of making sure that the variable can not be overriden or modified so that the variable acts like a constant. wikipedia article on final.

The values specified in an enum are constants so you can choose between using what you have, a constant, or using an enum, a constant, however using the enum will provide a safety check from the compiler so that only the specified values of the enum can be used in a method call or variable assignment for nanoseconds.

Here is an explanation of final with additional links from that stack overflow. Java method keyword final and its use also provides some additional information.

See What is the purpose of Enum for some explanation about enum.

Community
  • 1
  • 1
Richard Chambers
  • 16,643
  • 4
  • 81
  • 106