Evorlor
Evorlor

Reputation: 7569

When should I use the final keyword instead of enums?

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?

Upvotes: 2

Views: 1845

Answers (5)

mprivat
mprivat

Reputation: 21902

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.

Upvotes: 6

Richard Chambers
Richard Chambers

Reputation: 17593

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.

Upvotes: 1

EpicPandaForce
EpicPandaForce

Reputation: 81568

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.

Upvotes: 4

Samuel Edwin Ward
Samuel Edwin Ward

Reputation: 6675

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.

Upvotes: 3

dimo414
dimo414

Reputation: 48864

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.

Upvotes: 6

Related Questions