1

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!

3
  • Is there a reason why you've put your enum inside MYConstants, instead of stand-alone? Commented Feb 10, 2014 at 23:45
  • I think a Class would work better in this situation. Commented Feb 11, 2014 at 0:02
  • @OP you have several answers here; please accept one of them if it answered your question. Commented Feb 14, 2014 at 0:12

5 Answers 5

2

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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;
  }
}

Comments

1

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());
    }

}

2 Comments

Don't you need to add an integer field to the enum for this to work?
Ah, the battle between the Null Object Pattern and throwing exceptions commences...
0

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).

Comments

0

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();

4 Comments

Unless I'm very much mistaken, enum values really should be written in all caps. Otherwise a good post.
@ABoschman - That is a hangover from the old C days when it was difficult to tell an important to know what was constant and what wasn't. Java is not C.
Aw, I've been doing these wrong as well? My professors have some explaining to do.
Well, if you're right and I'm wrong, at the very least it's a very contested issue. Most of the sources I can find state that they should be all caps, including four of the posters on this page and the oracle docs website: docs.oracle.com/javase/tutorial/java/javaOO/enum.html

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.