Java Enum and Android Intdef/Stringdef annotation

本文探讨了在Java中使用枚举(Enum)和Android中的IntDef注解来限定变量取值的方法,比较了整型常量、枚举及IntDef的优缺点,并介绍了如何在Android应用中正确使用IntDef。

本文转载自: https://noobcoderblog.wordpress.com/2015/04/12/java-enum-and-android-intdefstringdef-annotation/

参考资料:http://developer.android.com/reference/android/support/annotation/IntDef.html

When we want a variable x to have values from some predefined constants then what can we do. We can declare the constant variables and set x from these constants. Lets assume x is currentDay and it can have any value from sunday to friday. We can code like this in java using integer constants.

public class Main {
 
    public static final int SUNDAY = 0;
    public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
    public static final int THURSDAY = 4;
    public static final int FRIDAY = 5;
    public static final int SATURDAY = 6;
 
    private int currentDay = SUNDAY;
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Main obj = new Main();
        obj.setCurrentDay(WEDNESDAY);
 
        int today = obj.getCurrentDay();
 
        switch (today) {
        case SUNDAY:
            System.out.println("Today is SUNDAY");
            break;
        case MONDAY:
            System.out.println("Today is MONDAY");
            break;
        case TUESDAY:
            System.out.println("Today is TUESDAY");
            break;
        case WEDNESDAY:
            System.out.println("Today is WEDNESDAY");
            break;
        case THURSDAY:
            System.out.println("Today is THURSDAY");
            break;
        case FRIDAY:
            System.out.println("Today is FRIDAY");
            break;
        case SATURDAY:
            System.out.println("Today is SATURDAY");
            break;
 
        default:
            break;
        }
    }
 
    public void setCurrentDay(int currentDay) {
        this.currentDay = currentDay;
    }
 
    public int getCurrentDay() {
        return currentDay;
    }
 
}

Problem with this code is I can set any integer value to currentDay.

obj.setCurrentDay(100);

and compiler will not give me any error. Then in switch/case we will miss that value. So Java gives us a solution that is Enumeration or Enum. If We rewrite the code with Enum in Java.

public class Main {
 
    public enum WeekDays {
        SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
    }
 
    private WeekDays currentDay = WeekDays.SUNDAY;
 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Main obj = new Main();
        obj.setCurrentDay(WeekDays.WEDNESDAY);
 
        WeekDays today = obj.getCurrentDay();
 
        switch (today) {
        case SUNDAY:
            System.out.println("Today is SUNDAY");
            break;
        case MONDAY:
            System.out.println("Today is MONDAY");
            break;
        case TUESDAY:
            System.out.println("Today is TUESDAY");
            break;
        case WEDNESDAY:
            System.out.println("Today is WEDNESDAY");
            break;
        case THURSDAY:
            System.out.println("Today is THURSDAY");
            break;
        case FRIDAY:
            System.out.println("Today is FRIDAY");
            break;
        case SATURDAY:
            System.out.println("Today is SATURDAY");
            break;
 
        default:
            break;
        }
    }
 
    public void setCurrentDay(WeekDays currentDay) {
        this.currentDay = currentDay;
    }
 
    public WeekDays getCurrentDay() {
        return currentDay;
    }
 
}

Now we have type safety. I can not have any value other then WeekDays in currentDay variable. That is a great improvement, and we should use it. But in Android there is a problem.

Enum in Android: Enum is a full fledged class in Java. Every value of Enum is an object of that Enum class. So Enum values will take more memory then int constant we used earlier. Even in old android devices (<=2.2), there were some performance issue related to Enum which were solved in JIT compiler. Now we can use Enum in Android Application, but if our application is a memory hungry application or a game application then we better use integer constants instead of Enum. But then problem remains.

There is a solution. Android support annotation library has some good annotation helper which can be used to find bug earlier (in compile time). IntDef and StringDef are two Magic Constant Annotation which can be used instead of Enum. These will help us to check variable assignment like Enum in compile time. Following code showed how to use IntDef instead of Enum.

public class MainActivity extends Activity {
 
    public static final int SUNDAY = 0;
    public static final int MONDAY = 1;
    public static final int TUESDAY = 2;
    public static final int WEDNESDAY = 3;
    public static final int THURSDAY = 4;
    public static final int FRIDAY = 5;
    public static final int SATURDAY = 6;
 
    @IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})
    @Retention(RetentionPolicy.SOURCE)
    public @interface WeekDays {}
 
    @WeekDays int currentDay = SUNDAY;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setCurrentDay(WEDNESDAY);
 
        @WeekDays int today = getCurrentDay();
 
        switch (today){
            case SUNDAY:
                break;
            case MONDAY:
                break;
            case TUESDAY:
                break;
            case WEDNESDAY:
                break;
            case THURSDAY:
                break;
            case FRIDAY:
                break;
            case SATURDAY:
                break;
            default:
                break;
        }
 
    }
 
    public void setCurrentDay(@WeekDays int currentDay) {
        this.currentDay = currentDay;
    }
 
    @WeekDays
    public int getCurrentDay() {
        return currentDay;
    }
}

Now we can not set any value other than WeekDays in currentDay or today variable. Compiler will check it and will give error. And if we use Android Studio, IDE will give suggestion about the value. So how to use it. At first declare the constants.

public static final int SUNDAY = 0;
public static final int MONDAY = 1;
public static final int TUESDAY = 2;
public static final int WEDNESDAY = 3;
public static final int THURSDAY = 4;
public static final int FRIDAY = 5;
public static final int SATURDAY = 6;

Then declare the @IntDef for these constants,

@IntDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})
@Retention(RetentionPolicy.SOURCE)
public @interface WeekDays {}

To set a variable of WeekDays type, so that no value other than weekdays can be set to that variable, we declare it like following,

@WeekDaysintcurrentDay ;

Now if there is any assignment which set currentDay to any other value than WeekDays, compiler will give a error. To set function parameter and function return type with WeekDays type,

public void setCurrentDay(@WeekDaysintcurrentDay) {
    this.currentDay = currentDay;
}
 
@WeekDays
public int getCurrentDay() {
    returncurrentDay;
}

@StringDef can be used in same manner.

public class MainActivity extends Activity {
 
    public static final String SUNDAY = "sunday";
    public static final String MONDAY = "monday";
    public static final String TUESDAY = "tuesday";
    public static final String WEDNESDAY = "wednesday";
    public static final String THURSDAY = "thursday";
    public static final String FRIDAY = "friday";
    public static final String SATURDAY = "saturday";
 
 
    @StringDef({SUNDAY, MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY})
    @Retention(RetentionPolicy.SOURCE)
    public @interface WeekDays {}
 
 
    @WeekDays String currentDay = SUNDAY;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setCurrentDay(WEDNESDAY);
 
        @WeekDays String today = getCurrentDay();
 
 
        switch (today){
            case SUNDAY:
                break;
            case MONDAY:
                break;
            case TUESDAY:
                break;
            case WEDNESDAY:
                break;
            case THURSDAY:
                break;
            case FRIDAY:
                break;
            case SATURDAY:
                break;
            default:
                break;
        }
 
    }
 
    public void setCurrentDay(@WeekDays String currentDay) {
        this.currentDay = currentDay;
    }
 
    @WeekDays
    public String getCurrentDay() {
        return currentDay;
    }
}

To use this feature, you have to add support-annotations library to your project. If you use Android Studio, then add following in your Gradle dependency.

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    ...
    compile'com.android.support:support-annotations:22.0.0'
}

You can learn more about support annotation library here.  And below is android performance patterns video about price of Enum.

Java中,一个枚举类型是由一组常量所组成的。这些常量在编译时就已经确定,因此与普通的变量不同,枚举类型的值不能随意改变。 有时候我们需要将一个枚举类型的值转换成整数或字符串类型,或者将一个整数或字符串类型的值转换为枚举类型。这时,我们可以使用Java中提供的一些方法来实现。 如果我们要将一个枚举类型的值转换为整数类型,可以使用枚举类型中的ordinal()方法。该方法返回该枚举常量在枚举类型中的序号,从0开始计数。示例代码如下: ``` enum Color{ RED, GREEN, BLUE } Color color = Color.RED; int index = color.ordinal(); // 0 ``` 如果要将一个整数类型的值转换成枚举类型,可以使用枚举类型中的values()方法。该方法返回一个包含所有枚举常量的数组。我们可以利用这个数组和整数类型的值来获取要转换的枚举类型。示例代码如下: ``` enum Color{ RED, GREEN, BLUE } int index = 1; Color color = Color.values()[index]; // GREEN ``` 如果要将一个枚举类型的值转换为字符串类型,可以使用枚举类型中的name()方法。该方法返回该枚举常量的名称。示例代码如下: ``` enum Color{ RED, GREEN, BLUE } Color color = Color.RED; String name = color.name(); // "RED" ``` 如果要将一个字符串类型的值转换为枚举类型,可以使用枚举类型中的valueOf()方法。该方法接受一个字符串类型的参数,并返回相应的枚举常量。需要注意的是,该方法对于不存在的枚举常量或空字符串会抛出IllegalArgumentException异常。示例代码如下: ``` enum Color{ RED, GREEN, BLUE } String name = "GREEN"; Color color = Color.valueOf(name); // GREEN ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值