user3013612
user3013612

Reputation: 61

java simple switch with enum

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

Answers (5)

Boris the Spider
Boris the Spider

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

OldCurmudgeon
OldCurmudgeon

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

peter.petrov
peter.petrov

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

Jason Schindler
Jason Schindler

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

Kevin Seifert
Kevin Seifert

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

Related Questions