为enum.ordinal

时间:2016-11-28 18:05:30

标签: java enums static-analysis

使用Java 7+ ....假设我们创建了一个枚举:

enum Foo{ FOO, BAR }

然后Foo.FOO.ordinal() == 0。但是,如果我重新排序枚举,请说:

enum Foo{ BAR, FOO }

然后Foo.FOO.ordinal() == 1。对于大多数人来说这是令人惊讶的,因为他们认为重新排序领域是一种“安全”的操作。毫无疑问,在大多数情况下,Java建议使用enum.ordinal() 反对。有很多替代方案,最明显(并且自我记录)将每个枚举值与int相关联。

不幸的是,我公司的某些人没有收到备忘录,而且我们的许多旧代码在整个地方使用.ordinal()方法,这取决于int和enum值之间关联的基本方式。当我有时间时,我会经历并重构,但它不会阻止新代码使用.ordinal(),这会引入可能无法追踪的错误。

原来如此!假设我有一个与它相关的很多结构的枚举。我可以以某种方式将.ordinal()标记为不安全,这样如果有人使用(比方说)Foo.FOO.ordinal(),就会生成编译器警告吗?

我满足于为此目的使用外部包,但如果它们不是太模糊,我会更喜欢它。

2 个答案:

答案 0 :(得分:1)

enum的重点是将代码与基础值分离,并使用ordinal()使目的失败。

您没有说,但我怀疑问题出现在Java代码和外部存储之间的接口上,即使用ordinal()将枚举“序列化”为可以存储在文件或数据库中的内容。

我觉得你在这里运气不好。正如@Henry所说,你唯一的选择可能是一个代码分析工具,它带有一个自定义规则来标记ordinal()的所有用法,以及完成四项任务的大量重构工作:

  1. 将每个枚举声明修改为不可变且永久性地将整数值附加到每个枚举值,与ordinal()无关。
  2. 对于每个枚举声明,添加一个返回整数值的方法int toInteger()
  3. 对每个枚举声明,添加方法static EnumClassName fromInteger(int v)以“反序列化”外部值
  4. 重构对ordinal()的所有引用,以使用新的toInteger()fromInteger()方法。

答案 1 :(得分:0)

这个XPath PMD规则怎么样?

// PrimaryPrefix / Name [ends-with(@ Image,'。arinal')]

将它放在规则元素中的规则集XML文件中,如下所示:

<rule name="DontUseEnumOrdinal" message="Please no enums ordinal"
    class="net.sourceforge.pmd.lang.rule.XPathRule" language="java">
    <description>We don't take kindly enum ordinal() round these parts</description>
    <priority>3</priority>
    <properties>
        <property name="xpath">
            <value><![CDATA[//PrimaryPrefix/Name[ends-with(@Image, '.ordinal')]]]></value>
        </property>
    </properties>
    <example><![CDATA[MyEnum.MY_VALUE.ordinal(); //is bad
        MyEnum.MY_VALUE.index(); //is better]]>
    </example>
</rule>