【发布时间】:2017-01-05 09:12:57
【问题描述】:
只要我记得,我就一直错过 Java 中的类型别名(例如 c++ 中的 typedef 或 haskell 中的 type/newtype)。
在 Android SDK 中,我们有 support annotations,其中包括 @IntDef、@StringDef 和各种资源类型注释,这有助于我们在编译时找出可能的整数/字符串值滥用。我正在插入一段来自 Android 文档的代码来给你一个简短的想法:
@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
@Retention(RetentionPolicy.SOURCE)
public @interface NavigationMode {}
public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;
@NavigationMode
public abstract int getNavigationMode();
public abstract void setNavigationMode(@NavigationMode int mode);
实际上,95% 的我想要类型别名的情况都差不多:当我得到某种数据库行 ID,通常是 long 或 String,这导致必须在名称中编码有关变量的类型信息(例如long folderId、long messageId)。但是,StringDef/IntDef 注解有一个恼人的限制:由于某种原因,它们需要一组预定义的常量,因此您只能描述一组有限的值,这对于 DB 标识符显然是不够的。
我想要的是某种类似的注释,比如 @TypeAlias 和一个 Lint 检查,所以我可以这样做:
@TypeAlias
@Retention(RetentionPolicy.SOURCE)
public @interface FolderId { }
@FolderId
public long getFolderIdByName(Database db, String name) {
long id = db.foldersTable().findByName(name).getId();
return id;
/*
we might need to suppress the check here
(because we pass long as a @FolderId long),
but that's okay, since we are aware of
what we are doing here, and it's the only
possible injection point for @FolderId
*/
}
public void deleteMessagesIn(Database db, @FolderId long folder) {
// whatever
}
public void deleteMessagesInInbox(Database db) {
deleteMessagesIn(db, 1); // rejected by Lint, trying to pass long as @FolderId long
deleteMessagesIn(db, getFolderIdByName(db, "Inbox")); // ok, passes Lint check
}
我看不出将类型别名注释限制为一组有限值的任何充分理由,我们可以通过如上所述的抑制来解决它,或者可以通过专门为提供类型别名的函数引入另一个注释来解决它。
更重要的是,这不仅与 Android 注释的限制有关:任何普通的 Java 应用程序也可以从这些类型的别名中受益,而且我没有设法在谷歌上搜索到任何类似的东西。我们还可以从使用TYPE_PARAMETER 目标中受益,这将使所有目标看起来几乎就像真正的类型别名。
所以问题是:
- 是否有执行此类检查的静态分析器?
- 如果没有,是否有任何我遗漏的基本限制阻碍了它的实施?从那以后,我觉得这很有用,所以如果没有的话,有人会这样做的。
附: @mernst 向我介绍了 Checker 框架,我设法以一种相对轻松的方式将其与 Android 集成:https://github.com/karlicoss/checker-fenum-android-demo
【问题讨论】:
标签: java android types annotations type-alias