1

I have three cases I want to test using a switch statement (instead of else if). Now those cases each test if the variable is instanceof a class. I want to do something like this:

switch(var){

case A: doA();
case B: doB();
case C: doC();

} 

public enum{
A, B, C
}

I want A to represent the case in which var instanceof A. Is there a way to assign this information to a value in an enum?

dot
  • 87
  • 1
  • 3
  • 13
  • 2
    But `A` already is an enum. I'm not sure what you're asking. – Dave Newton Jan 26 '17 at 19:11
  • I'm not sure how the program will know that case A means that `var instanceof class A` – dot Jan 26 '17 at 19:13
  • That is not valid Java code: The enum class must have a name. Also, what is the type of variable `var`? If the enum is named `X`, i.e. `public enum X { A, B, C }`, and `var` is an `X`, then your code is complete and valid, though you probably want to add some `break` statements. – Andreas Jan 26 '17 at 19:15
  • Possible duplicate of [Switch on Enum in Java](http://stackoverflow.com/questions/6391777/switch-on-enum-in-java) – Nir Alfasi Jan 26 '17 at 19:19
  • and http://stackoverflow.com/questions/5551568/compilation-error-switch-with-enum – Nir Alfasi Jan 26 '17 at 19:19
  • 1
    I think neither switch-case nor if-then-else statements should be used here. If you want to execute different code depending on the actual class of your object `var`, than you should use method overloading. – dpr Jan 26 '17 at 19:19

4 Answers4

0

You first need to give your enum a name.

public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY 
}

public class EnumTest {
Day day;

public EnumTest(Day day) {
    this.day = day;
}

public void tellItLikeItIs() {
    switch (day) {
        case MONDAY:
            System.out.println("Mondays are bad.");
            break;

        case FRIDAY:
            System.out.println("Fridays are better.");
            break;

        case SATURDAY: case SUNDAY:
            System.out.println("Weekends are best.");
            break;

        default:
            System.out.println("Midweek days are so-so.");
            break;
    }
}

public static void main(String[] args) {
    EnumTest firstDay = new EnumTest(Day.MONDAY);
    firstDay.tellItLikeItIs();
    EnumTest thirdDay = new EnumTest(Day.WEDNESDAY);
    thirdDay.tellItLikeItIs();
    EnumTest fifthDay = new EnumTest(Day.FRIDAY);
    fifthDay.tellItLikeItIs();
    EnumTest sixthDay = new EnumTest(Day.SATURDAY);
    sixthDay.tellItLikeItIs();
    EnumTest seventhDay = new EnumTest(Day.SUNDAY);
    seventhDay.tellItLikeItIs();
}
}

The example is taken from enums in the Java SE tutorials page. This is exactly your use case.

https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

ucsunil
  • 7,378
  • 1
  • 27
  • 32
0

Declare enum like below:

private enum ClassType {
    A,
    B,
    C,
    D,
    Unknown;
}

Now, write a method to return type:

private ClassType getClassType(Object object){
    ClassType type = null;
    try{
        type = ClassType.valueOf(object.getClass().getSimpleName());
    }catch(IllegalArgumentException e){
        type = ClassType.Unknown;
    }
    return type;
}

Now, use it with switch:

switch(getClassType(object)){
    case ClassType.A:
        //do something
        break;
}

For new classes, you need to add a value and case in switch.

Darshan Mehta
  • 30,102
  • 11
  • 68
  • 102
0

Not sure why you want the enum. Ever since Java 7, you can switch on Strings. So one option is

switch(myObject.getClass().getCanonicalName()) {
  case "java.lang.String" : doA(); break;
  case "com.Acme.foobar" : doB(); break;
  default: throw new IllegalArgumentException();
}

That said, if the classes are related, and you have control of them, then @dpr is right: it is probably better to use polymorphism and overloading.

user949300
  • 15,364
  • 7
  • 35
  • 66
  • 2
    Because enums are better than strings, almost always. They're typesafe, you can't fat-finger them, etc. – Dave Newton Jan 26 '17 at 19:42
  • @Dave - agree 100%. But for this particular case the enum for a class feels very clunky. Darshan's code work, but adds very little, is no more typo-safe, feels like overengineering, and will be just as hard to maintain as you add more and more options. – user949300 Jan 26 '17 at 19:44
  • I'll try this, thank you! I'm not familiar with method overloading, so I guess this is my first stop in solving this – dot Jan 26 '17 at 20:52
  • Okay I realize now that my cases aren't all `instanceof` checks, one of them is a boolean. Seems like I'm stuck if I try it this way. – dot Jan 26 '17 at 21:03
0

I would use a map to map a runtime type to an enum constant, for example:

public enum ClassType{
    A(Integer.class),
    B(String.class),
    C(Object.class),
    UNKNOWN(null);      

    private static final Map<Class<?>, ClassType> typesMap = new HashMap<>();
    public final Class<?> type;

    static{
        for (ClassType classType : EnumSet.allOf(ClassType.class)){             
            if(classType.type != null){
                typesMap.put(classType.type, classType);
            }
        }
    }

    private ClassType(Class<?> type){
        this.type = type;           
    }

    public static ClassType getClassTypeOf(Class<?> type){
        return typesMap.getOrDefault(type, UNKNOWN);
    }
}

It could be used like this:

switch(ClassType.getClassTypeOf(var.getClass())){
    case A:         
        break;
    case B:         
        break;
    case C:
        break;          
    default:            
        break;      
}

However, this version does not consider supertypes of the type of var. To support supertype lookups you can change the getClassTypeOf-method to:

public static ClassType getClassTypeOf(Class<?> type){      
    for(Class<?> lookupType = type; lookupType != null; lookupType = lookupType.getSuperclass()){
        ClassType classType = typesMap.get(lookupType);
        if(classType != null){
            return classType;
        }
    }       
    return UNKNOWN;
} 
Calculator
  • 2,769
  • 1
  • 13
  • 18