java创建枚举时报错_容易出错的Java枚举重构

我正在重构一些旧代码以使用enum而不是String常量。当我检查代码时,发现比较enum和String不会引发异常。我不能删除旧的常量,因为其他项目仍在使用它们。

我不能覆盖等号,因为JLS特别禁止:

The equals method in Enum is a final method that merely invokes

super.equals on its argument and returns the result, thus performing

an identity comparison.

代码如下:

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也没有报告任何错误。有什么我可以保护的吗?

您可以将==与枚举一起使用。

我的问题是万一我错过了什么

但是,您是否没有类型检查在哪里传递这些常量?也就是说,预期String的方法在编译时会大喊您正在向它们传递枚举?或者你只是使用Object还是原始列表?

有一个方法像getgender,它返回了一个字符串;现在它返回了一个枚举,所以代码仍然有效。

@真正的怀疑论者你可以通过CONSTANT.name()。但是,如果该方法需要一个String,那么您还没有充分认识到使用enum的优势。该方法应该是一个Gender。

@hovercraftfullofeels是的,但是对于一个普通的对象,您可以用equals捕捉它并抛出一个异常;对于一个枚举,我不能;它只返回false

@凯文克鲁姆维德,我想你误解了我的要求。我没有想到一种方法来绕过不兼容性——这不是OP要求的。我正在考虑一种使用类型安全的方法来帮助防止这种混淆。

"对于一个常规对象,您可以在equals中捕获它并抛出一个异常"——您可以,但不应该。当传递了错误的类型时,重写的equals(...)方法应该返回false,就像enum方法一样。

我说不出你到底想要什么。您想要一种方法来编写这个"重构"类,这样就不会发生混淆了吗?是否希望使用一种方法将枚举的使用与字符串的使用分开?是否希望有一种方法来编写它,以便在字符串的使用开始与枚举的使用混合时显示错误?什么?

从equals中抛出一个异常(NPE除外),肯定会破坏最小惊异原则(和合同)。

@当getgender返回枚举时,arcy只是一种捕获方法,如果我错过了obj.getgender().equals("male")。

@KevinKrumwiede是完全正确的:你不应该从等号中抛出异常。

@它甚至不应该抛出NPE。如果你通过了null,它应该只返回false。这就是sdk类所做的,以及Eclipse生成的equals(...)方法所做的。

@凯文克鲁姆维德,我同意合同没有提到扔核电站,这样做将违反公约。然而,也有人认为合同本身已经破裂。关于中的主题的好讨论是,如果等于(空)而引发NullPointerException是一个坏主意。

如注释所述,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";

使用javac -Xlint:deprecation编译将对@Deprecated项的所有使用发出警告(在eclipse等中也有这些选项),这将有助于消除字符串未被枚举替换时出现的遗漏。

我会这样做:

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

通过将字符串转换为枚举的一个实例,然后比较两个枚举,可以得到更可靠的结果。

您可以将最后一个字符串变量移动到一个单独的类中,比如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)。

移动它们会破坏源代码兼容性。OP提到其他项目正在使用这些常量,所以这将是非常糟糕的。

是的,但是对于大多数现代的IDES,查找字符串常量和前置StringConstants的所有用法是非常简单的。

您不应该强迫其他开发人员这样做。一旦一个公共API脱离了alpha,你就应该考虑它是用石头雕刻的。改变它看起来非常不称职和不专业。对公共API进行破坏性更改的唯一时间是当您遇到主版本号时。即便如此,只有在必要时才进行功能更改,而不仅仅是重新组织或重命名事物。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值