我正在重构一些旧代码以使用enum
代替String
常量。当我发现比较enum
到String
不会抛出异常时,我正在审核我的代码。我无法删除旧常量,因为其他项目仍在使用它们。
我无法覆盖等于,因为JLS明确禁止这样做:
Enum中的equals方法是一个仅调用的最终方法 对其参数进行super.equals并返回结果,从而执行 身份比较。
代码如下所示:
public enum Gender{
MALE,
FEMALE
}
// Constants for genders
public static final String MALE = "Male";
public static final String FEMALE = "Female";
//following are obviously false
MALE.equals(Gender.MALE)
Gender.MALE.equals(MALE)
对于常规对象,我可以覆盖equals并抛出异常,但对于我的示例,它将返回false。还有一个类似getGender的方法,它返回一个字符串,现在返回一个枚举,所以我可以错过一些地方,并将一个字符串与枚举进行比较
这很容易出错。 FindBugs也没有报告任何错误。 无论如何我可以防止这种情况吗?
答案 0 :(得分:5)
如评论中所述,Object#equals(...)
不是类型安全的。您无法阻止API的用户将其传递给错误类型的对象。在那种情况下,它应该只返回false
。如果有人这样做,最终他们会注意到它总是返回错误并去寻找错误。
您应该弃用String
常量以引起对首选方式的注意:
/**
* New code should use {@link Gender#MALE}.
*/
@Deprecated
public static final String MALE = "Male";
/**
* New code should use {@link Gender#FEMALE}.
*/
@Deprecated
public static final String FEMALE = "Female";
答案 1 :(得分:2)
我会做这样的事情:
public enum Gender {
MALE("Male"),
FEMALE("Female");
private final String val;
Gender(String val) {
this.val = val;
}
public static Gender getEnum(String value) {
for (Gender a : values()) {
if (a.getVal().equalsIgnoreCase(value)) {
return a;
}
}
return throw new IllegalArgumentException("no gender known");
}
public String getVal() {
return val;
}
}
它允许您从字符串创建枚举的实例,然后比较枚举
Gender genderFromString = Gender.getEnum(someString);
genderFromString.equals(Gender.MALE);
通过将字符串转换为枚举的实例然后比较2个枚举,可以获得更可靠的结果
答案 2 :(得分:1)
您可以将最终的String变量移动到一个单独的类中,比如StringConstants
。
public class StringConstants {
public static final String MALE = "Male";
public static final String FEMALE = "Female";
}
然后在您的代码中,当有人试图将StringConstants.MALE
与Gender.MALE
进行比较时,这将是一个更明显的错误。
此外,将枚举重命名为GenderEnum
可能会有所帮助,因为这样更明显的是你不想做GenderEnum.MALE.equals(StringConstants.MALE)
。