Java Enum枚舉替代方案--Android IntDef/StringDef Annotation註解

原文鏈接:https://noobcoderblog.wordpress.com/2015/04/12/java-enum-and-android-intdefstringdef-annotation/


當我們想把一個變量x的取值限制在幾個預先定義的常量時,我們會怎麼做呢?我們可以先定義一些常量值,然後從這些常量中選擇賦值給x。下面,讓我們假設變量x爲currentDay,它的取值包含了星期天到星期五。我們可以在Java中,通過Integer的常量寫出下面的代碼:

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

但上面的代碼會出現的問題是:我可以爲currentDay設置任何的int值

obj.setCurrentDay(100);

這種情況編譯器並不會給出任何的錯誤提示。然後我們的switch/case語句會忽略掉處理這種情況。因此,對於這種情況,Java爲我們提供了一種叫Enumeration(或稱Enum,枚舉)的解決方案。如果使用了Enum枚舉,我們的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;
    }
 
}

現在我們擁有了類型安全的保障。這裏我們不能再爲currentDay賦予任何在WeekDays以外的值了。這是一個很大的進步,我們都應該使用多多使用。不過在Android中,這裏會存在一些問題。

Enum枚舉在Android中:Enum在Java中是一個完全成熟的class。在Enum枚舉中的每一個值,都是Enum枚舉類型中的一個對象實例。因此,Enum枚舉值會比我們之前使用的常量類型佔用更多的內存。即使在舊Android設備(版本 <= 2.2)上,這裏也存在一些由JIT即使編譯器解決的,由Enum枚舉類型引發的性能問題。現在我們可以在Android應用中使用Enum枚舉類型,但如果我們的應用是一種非常喫緊內存的類型或者是遊戲應用,那麼我們最後使用int常量來代替Enum枚舉。但這導致我們上面提及的問題依然存在。


現在我們有了別的解決方案。Android的support Annotation註解庫有一些很好的annotation註解來幫助我們更早的發現bug(在編譯時期)。IntDef 和 StringDef 是兩個非常有魔力的Constant Annotation註解,我們可以使用它們來代替Enum枚舉。它們會幫助我們像Enum枚舉一樣,在編譯時期檢查變量的賦值情況。下面的代碼展示給我們如何使用IntDef代替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;
    }
}

現在我們不能再爲currentDay和today賦予任何在WeekDays以外的值了。編譯器會檢查變量的賦值情況,並反饋給我們相應的錯誤信息。如果我們使用Android Studio,IDE還會向我們提供變量建議的功能(代碼提示)。當我們使用時,首先需要定義一些常量:

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註解聲明這些變量

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

我們可以通過下面的代碼,設置一個變量爲WeekDays類型,讓WeekDays以外的值都無法賦給該變量

@WeekDays int currentDay ;

現在,當我們想爲currentDay賦予任何在WeekDays以外的值時,編譯器會提示我們相應的錯誤信息。設置方法的參數以及返回值爲WeekDays的方法如下:

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

@StringDef也能以同樣的方式應用

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

想要使用以上的功能,你需要爲你的工程添加support-annotation庫的依賴。如果你使用的是Android Studio,那麼請在你的Gradle依賴腳本下添加下面代碼

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

你可以點擊這裏查看更多關於Android support annotation庫的內容。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章