Finlay Smith
Finlay Smith

Reputation: 251

Benefits of using Enums over Collections

I'm trying to check if a users account type matches one of several Strings.

There's debate in the office as to whether this should be represented as an enum with each entry containing a different string, or as a Set of Strings. Whilst the Set may be more efficient, an enum may be stylistically superior as it is clearer it is being used for logic flow.

What are the advantages of these two approaches?

Upvotes: 21

Views: 2109

Answers (7)

Konstantin Yovkov
Konstantin Yovkov

Reputation: 62864

Indeed, a Set<String> is more efficient in terms of performance when searching. However, I wouldn't expect that you have thousands of account types, but several, so you won't actually feel the difference when searching. There's one problem with this approach, though - you will be able to add any String to the Set, which is brittle.

My personal prefer would be to use an enum, especially if you don't expect that more account types will be introduced. And if you have a Set<AccountType> you'll be restricted with the values you can add (i.e. you will be able to add only account types, but not anything, like the approach with a Set<String>). The problem with this approach is the Open/Closed Principle - consider you have a switch statement over a AccountType variable with all the corresponding cases. Then, if you introduce a new AccountType constant, you must change the switch statement (with adding a new case), which breaks the "Open/Closed principle". In this case the neatest design would be to have an abstract class/interface, called AccountType which has all the specific account types as sub-classes.

So, there are several approaches you can follow, but before picking one, you should try answer yourselves the question of "How are we going to use it?"

Upvotes: 22

OldCurmudgeon
OldCurmudgeon

Reputation: 65813

I'd use a Map<String,Enum> = new HashMap<>(); for maximum efficiently.

Upvotes: 0

Brandon
Brandon

Reputation: 10028

It sounds to me like the problem is that you are using a string to represent data that can only have a few valid, known values. A Set may be helpful to validate if the string value is valid, but it doesn't prevent it from becoming invalid.

My suggestion is to define an enum with the valid account types and use that in place of strings. If you have input coming from the outside that represents an account type, then put a static method on the enum like "fromString" which returns an appropriate enum instance, thereby shortening the window of where invalid data be be a consideration.

You can create a Set of AccountType enum instances, provided you implement the appropriate Comparator, compareTo, or hashCode methods (depending on if you used TreeSet or HashSet, etc.). This could be useful if you have classifications of account types that you need to check against. For example, if there are "Local Admins", "Global Admins", and "Security Admins", you could define a method isAdmin(AccountType t) which searches a Set of AccountTypes. For example:

private Set<AccountType> ADMIN_ACCOUNT_TYPES = new HashSet<AccountType>() {{
    add(AccountType.LOCAL_ADMIN);
    add(AccountType.GLOBAL_ADMIN);
    add(AccountType.SECURITY_ADMIN);
}};

public boolean isAdmin(AccountType t) {
    return ADMIN_ACCOUNT_TYPES.contains(t);
}

Now, if you have a case where there are lots of different account types, with many groupings, and performance of lookups is a concern, this is how you could solve it.

Though to be honest, if you only have a few account types and they rarely change, this may be over-engineering it a bit. If there are only 2 account types, a simple if statement with equality check will be more efficient than a hash table lookup.

Again, performance may not really be a problem here. Don't over-optimize or optimize prematurely.

Upvotes: 3

Linus_30
Linus_30

Reputation: 191

In my experience, I suggest using enum in this case. Even mysql supports enum for use cases where you want a column to accept values from an explicitly declared list.

Upvotes: 1

RealSkeptic
RealSkeptic

Reputation: 34618

It is worth noting that an enum's valueOf(String) method is implemented using the Enum.valueOf(Class,String) method, which in turn is implemented using a HashMap.

This basically means that looking up the account type from the string by using AccountTypes.valueOf() is an O(1) operation and quite as efficient as a set operation. You can then use the returned value (the actual enum object) in the program, with full type safety, faster comparisons, and all the other benefits of the enum.

Upvotes: 3

lance-java
lance-java

Reputation: 27976

Enums are great because you get compile time checking. Invalid values simply won't compile so it 'fails fast'.

A collection of strings is great when you want to add another option without compiling/releasing a new version of your application. If, for instance, the valid options were configured in a database table.

Upvotes: 6

ReyCharles
ReyCharles

Reputation: 1792

An enum would be better since account types (typically) do not change dynamically. Furthermore, using an enum makes the types more precise - e.g. there's no way to mix up "Hello, World!" with an account type.

Upvotes: 13

Related Questions