自定义注解,代替枚举类型的运用
一、常量
比如做一个下载功能,有 等待、下载中、下载完成、下载失败、空 几种状态,我们可以定义一组常量来表示
public class DownloadStatusConst {
public static final int NONE = 0;
public static final int WAIT = 1;
public static final int DOWNLOADING = 2;
public static final int COMPLETE = 3;
public static final int ERROR = 4;
}
下载方法接收一个整型参数,表示状态
private void startDownloadConst(int status) {
switch (status) {
case DownloadStatusConst.NONE:
MLog.log("none");
break;
case DownloadStatusConst.WAIT:
MLog.log("start download");
break;
case DownloadStatusConst.DOWNLOADING:
MLog.log("download...");
break;
case DownloadStatusConst.COMPLETE:
MLog.log("complete");
break;
case DownloadStatusConst.ERROR:
MLog.log("error");
break;
}
}
使用时则可以这样调用
startDownloadConst(DownloadStatusConst.WAIT);
上面这样写用起来代码没有错误,但是使用时别人调用你的方法startDownloadConst时,由于接收的是一个整型参数,没有约束,别人可以随意传入,比如传个-1,或者完成了传了个4。这样代码没有出错,但是逻辑出问题了,还不好排查。
二、枚举
为解决上面的问题,定义一个枚举类
public enum DownLoadStateEnum {
NONE,
WAIT,
DOWNLOADING,
COMPLETE,
ERROR
}
方法需要传入一个枚举类型的参数
private void startDownload(DownLoadStateEnum status) {
switch (status) {
case NONE:
MLog.log("none");
break;
case WAIT:
MLog.log("start download");
break;
case DOWNLOADING:
MLog.log("download...");
break;
case COMPLETE:
MLog.log("complete");
break;
case ERROR:
MLog.log("error");
break;
}
}
使用时就很方便类,根据枚举中的名称就可以准确的使用了
startDownload(DownLoadStateEnum.WAIT);
使用枚举很好的解决了上面的问题,而且看过 Effective Java 这本书的应该知道,推荐使用枚举代替常量,这在Java上是没问题的,其实在Android上也是没问题的,不过Android毕竟是个移动设备,对内存的使用要求很高,尽量是能省则省,使用枚举比使用普通常量会消耗更多的内存,具体可以谷歌一下。那么有没有什么可以替代枚举的方案,那就是注解
三、自定义注解
@Retention(RetentionPolicy.SOURCE)
public @interface DownLoadState {
int NONE = 0;
int WAIT = 1;
int DOWNLOADING = 2;
int COMPLETE = 3;
int ERROR = 4;
}
自定义注解使用@interface修饰,同接口的功能,里面的字段全部是 public static final 类型的。使用 RetentionPolicy.SOURCE 说明注解是源码级别的,注解信息只会保留在java文件里。关于 Retention 可以看上一讲。
然后使用时只需要将自定义注解修饰在需要的地方
private void startDownload(@DownLoadState int status) {
switch (status) {
case DownLoadState.NONE:
MLog.log("none");
break;
case DownLoadState.WAIT:
MLog.log("start download");
break;
case DownLoadState.DOWNLOADING:
MLog.log("download...");
break;
case DownLoadState.COMPLETE:
MLog.log("complete");
break;
case DownLoadState.ERROR:
MLog.log("error");
break;
}
}
上面使用 DownloadStatus 注解修饰参数 status ,在使用时
startDownload(-1);
如果传如任意数字,比如传如-1,便会有警告,提醒使用者,防止错误的发生。另外谷歌还提供了 Typedef 注解(IntDef 和 StringDef ),来辅助创建int和String类型的枚举注解
官网是这么说的:
Use the @IntDef and @StringDef annotations so you can create enumerated annotations of integer and string sets to validate other types of code references. Typedef annotations ensure that a particular parameter, return value, or field references a specific set of constants. They also enable code completion to automatically offer the allowed constants.
使用 @IntDef 和 @StringDef 注解,以便能够创建整型和字符串集的枚举注解来验证其他类型的代码引用。Typedef 注解可以确保特定参数、返回值或字段引用特定的常量集。它们还可以完成代码以自动提供允许的常量。
Typedef 的目的是防止在我们定义的常量值重复,所以上面的代码可以改为:
@IntDef({
DownLoadState.WAIT,
DownLoadState.DOWNLOADING,
DownLoadState.COMPLETE,
DownLoadState.ERROR,
DownLoadState.NONE
})
@Retention(RetentionPolicy.SOURCE)
public @interface DownLoadState {
int NONE = 0;
int WAIT = 1;
int DOWNLOADING = 2;
int COMPLETE = 3;
int ERROR = 4;
}
则当DownLoadStatus中的常量值相同时会报错。
使用如下:
startDownload(DownLoadState.WAIT );