Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method to limit potential values of an Enum

Is it possible to limit the valid enum values that a method can accept.

Say, for example, I have an enum like this:

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

And say I have a method that only should accept an inner set of those values:

//Here dayOfWeek should only be Monday - Friday.
public void setWorkDayAlarm(WEEKDAY dayOfWeek) {
}

I know you can obviously switch on the valid values, and in the default case not do anything. But is there a way (or a pattern) to define in the interface of the method, that it only accepts a certain subset of valid enums in Java (5+)?

like image 578
rouble Avatar asked Oct 14 '11 18:10

rouble


People also ask

Is there a limit to the number of values you can have in a enum?

Enums definitely have limits, with the primary (hard) limit around 32K values. They are subject to Java class maximums, both of the 'constant pool' (64K entries) and -- in some compiler versions -- to a method size limit (64K bytecode) on the static initializer.

Can you have methods in enums?

The enum class body can include methods and other fields. The compiler automatically adds some special methods when it creates an enum. For example, they have a static values method that returns an array containing all of the values of the enum in the order they are declared.

Can enums be protected?

Enum Fields The enum constructor must be private . You cannot use public or protected constructors for a Java enum . If you do not specify an access modifier the enum constructor it will be implicitly private .

Can you use abstract methods in enum?

Yes, you can define abstract methods in an enum declaration if and only if all enum values have custom class bodies with implementations of those methods (i.e. no concrete enum value may be lacking an implementation).


3 Answers

I don't know that the type system can help you here. What about something like this?

public enum DayOfWeek {
    SUNDAY(false), MONDAY(true), TUESDAY(true), WEDNESDAY(true),
    THURSDAY(true), FRIDAY(true), SATURDAY(false);

    private final boolean isWeekday;

    private DayOfWeek(boolean isWeekday) {
        this.isWeekday = isWeekday;
    }

    public boolean isWeekday() {
        return isWeekday;
    }
}

Then check the argument:

public void setWorkDayAlarm(DayOfWeek dayOfWeek) {
    if (!dayOfWeek.isWeekday())
        throw new IllegalArgumentException("Need weekday, got " + dayOfWeek);

    // ...
}
like image 136
pholser Avatar answered Nov 01 '22 05:11

pholser


The language itself provides no way to build subsets of an enum. That would defeat the purpose of an enum in the first place - to have a defined set of values for a given domain.

What you can do: Define another appropriate enum for that domain and provide reasonable cross-mappings. To get the idea:

public enum WORKDAY {
    MONDAY(WEEKDAY.MONDAY),
    TUESDAY(WEEKDAY.TUESDAY),
    WEDNESDAY(WEEKDAY.WEDNESDAY),
    THURSDAY(WEEKDAY.THURSDAY),
    FRIDAY(WEEKDAY.FRIDAY);

    final public WEEKDAY weekday;

    WORKDAY(WEEKDAY wd){
        this.weekday = wd;
    }
    static WORKDAY convertWeekday(WEEKDAY weekday){
        // in real live use a static EnumMap
        for(WORKDAY workday: values())
            if( workday.weekday == weekday )
                return workday;
        return null; // or an exception
    }
}

public void setWorkDayAlarm(WORKDAY workDay){ ... }

The good thing: The caller of the conversion method must deal with these values which are not mappable. Your method stays clean.

like image 24
A.H. Avatar answered Nov 01 '22 06:11

A.H.


Since the method you provided there is public, it is acceptable to throw an IllegalArgumentException if a caller gives it an invalid value. For a private method, you could have a debug assertion fail.

like image 28
David Avatar answered Nov 01 '22 07:11

David