Reputation: 251
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
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 case
s. 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
Reputation: 65813
I'd use a Map<String,Enum> = new HashMap<>();
for maximum efficiently.
Upvotes: 0
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
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
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
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
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