Reputation: 61
I feel like I am just missing something or maybe this is not the use of enum. Pretty much I know I could clean up this code using an enum:
int bookTypeId = 1; //dynamic
String bookTypeName;
switch (bookTypeId) {
case 1:
bookTypeName = "Fantasy";
break;
case 2:
bookTypeName = "Horror";
break;
case 3:
bookTypeName = "Action";
break;
default:
bookTypeName = "Error";
}
And so I did, I stored it in another class and it looks like:
public static enum BookType {
HORROR("Horror"), FANTASY("Fantasy"), ACTION("Action"), ERROR("Error");
private String name;
BookType(String name) {
this.name = name;
}
public String getType() {
return name;
}
}
Using it now like:
switch (bookTypeId) {
case 1:
bookTypeName = MYConstants.BookType.FANTASY.getType();
break;
case 2:
bookTypeName = MYConstants.BookType.HORROR.getType();
break;
case 3:
bookTypeName = MYConstants.BookType.ACTION.getType();
break;
default:
bookTypeName = MYConstants.BookType.ERROR.getType();
}
I want to take this one step further, and clean up my main class of this switch statement (which is sort of why I started looking at enums because right now it seems to do the same thing).
Is it possible to move this switch/case inside of the enum? And then use the enum in a way such as
bookTypeName = MYConstants.BookType.getType(bookTypeId);
Also is it also possible to declare this enum using final (which it currently is complaining about when I try), or is it already final?
Thanks!
Upvotes: 1
Views: 210
Reputation: 61128
Something like the below?
public static enum BookType {
HORROR(1, "Horror"),
FANTASY(2, "Fantasy"),
ACTION(3, "Action");
private static final Map<Integer, BookType> LOOKUP;
static {
LOOKUP = new HashMap<>();
for (final BookType type : values()) {
LOOKUP.put(type.id, type);
}
}
public static BookType getById(final int id) {
final BookType bt = LOOKUP.get(id);
if (bt == null) {
throw new IllegalArgumentException("Invalid book id " + id);
}
return bt;
}
private final int id;
private final String name;
BookType(final int id, final String name) {
this.id = id;
this.name = name;
}
public String getType() {
return name;
}
}
Usage:
final BookType type = BookType.getById(bookTypeId);
You can remove the String
property and override toString()
:
@Override
public String toString() {
final String name = name();
return name.substring(0, 1) + name.substring(1).toLowerCase();
}
To answer your last question, an enum
cannot be final
. enum
is syntactic sugar; the compiler will desugar it by first creating a class BookType extends Enum<BookType
and the creating static final
instances of the new class
with the specified names. The actual enum
declaration itself is not really a class
declaration so cannot be final
. Moreover, if your enum
constants themselves override or implement methods (like in this example) then each enum
constant will be an anonymous class extending Booktype
- if the enum
were final
and that was transposed onto the BookType
class then this behaviour would not be allowed; and it wouldn't be entirely obvious why.
Upvotes: 2
Reputation: 65793
Yes you are missing something and here it is. This is all you need.
enum Genre {
Unknown,
Fantasy,
Horror,
Action,
Romance;
}
You do not need to convert the result to and/or from an int
.
You do not need to transform it back and forth to/from a bookTypeId
, use valueOf
.
If you need to make a book type be something more than just the enum
then add attributes to it.
What you are missing is that the enum itself can be used elsewhere in you program, it can be saved to database by name and recovered through the valueOf
method.
Let your enum
be simple!
Instead of your switch - which seems to be getting a String
form of the enum
just do:
String name = genre.name();
Upvotes: 0
Reputation: 39437
I think you're looking for this pattern.
public enum BookType {
INVALID(0),
HORROR(1),
FANTASY(2),
ACTION(3),
ERROR(4);
private int value;
private BookType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public String toString(){
return super.toString().toLowerCase();
}
public static BookType getInstance(int value) {
for (BookType type : BookType.values()) {
if (value == type.value) {
return type;
}
}
return INVALID;
}
public static void main(String[] args){
BookType b1 = BookType.HORROR;
System.out.println(b1.toString());
BookType b2 = BookType.getInstance(3);
System.out.println(b2.toString());
}
}
Upvotes: 1
Reputation: 2960
It really depends on the significance of the relationship between id and name. I would try to eliminate the int id all together. If that isn't possible, consider making it a field in the enum.
public static enum BookType {
HORROR(1, "Horror"), FANTASY(2, "Fantasy"), ACTION(3, "Action"), ERROR(-1, "Error");
private String name;
private int typeCode;
BookType(int typeCode, String name) {
this.typeCode = typeCode;
this.name = name;
}
public String getName() {
return name;
}
public int getTypeCode(){
return typeCode;
}
public static BookType getFromTypeCode(int typeCode){
for(BookType bookType : BookType.values()){
if(bookType.getTypeCode() == typeCode){
return bookType;
}
}
return BookType.ERROR;
}
}
Upvotes: 1
Reputation: 3572
Your switch looks clean enough to me. If you want to generalize, I wouldn't move hard-coded business logic around to another block of hard-coded business logic. Push it to a config file or database. The cleaner approach is a lookup table (of sorts).
Upvotes: 0