Java枚举 - 为什么使用toString而不是name

时间:2012-11-08 14:35:57

标签: java enums

如果你在方法name()中查看enum api,它会说:

  

返回此枚举常量的名称,与其枚举声明中声明的完全相同。           大多数程序员应优先使用toString方法,           因为toString方法可能返回一个更加用户友好的名称。           此方法主要用于特殊情况,其中正确性取决于获取确切名称,不会因发行版本而异。

为什么最好使用toString()?我的意思是当name()已经是final时,可以覆盖toString。因此,如果您使用toString并且有人覆盖它以返回硬编码值,则整个应用程序都会关闭...另外,如果您查看源代码,则toString()方法将返回完全正确的名称。这是一回事。

7 个答案:

答案 0 :(得分:188)

这实际上取决于你想要对返回值做什么:

  • 如果您需要获取用于声明枚举常量的确切名称,则应使用name(),因为toString可能已被覆盖
  • 如果您想以用户友好的方式打印枚举常量,您应该使用可能已被覆盖的toString(或不!)。

当我觉得它可能令人困惑时,我会提供更具体的getXXX方法,例如:

public enum Fields {
    LAST_NAME("Last Name"), FIRST_NAME("First Name");

    private final String fieldDescription;

    private Fields(String value) {
        fieldDescription = value;
    }

    public String getFieldDescription() {
        return fieldDescription;
    }
}

答案 1 :(得分:53)

如果您想进行比较,请使用name()或在代码中使用硬编码值进行内部使用。

如果要向用户显示信息(包括查看日志的开发人员),请使用toString()。永远不要依赖toString()给出特定值的代码。切勿针对特定字符串进行测试。如果在有人正确更改toString()返回时您的代码中断,那么它已经被破坏了。

来自javadoc(强调我的):

  

返回对象的字符串表示形式。一般来说,   toString方法返回一个字符串“textually represent” this   宾语。结果应该是简洁但信息丰富的表示   一个人阅读很容易。 建议全部   子类重写此方法。

答案 2 :(得分:23)

name()enum的“内置”方法。这是最终的,你不能改变它的实现。它在写入时返回枚举常量的名称,例如:大写,没有空格等。

比较MOBILE_PHONE_NUMBERMobile phone number。哪个版本更具可读性?我相信第二个。这是不同的:name()始终返回MOBILE_PHONE_NUMBERtoString()可以覆盖以返回Mobile phone number

答案 3 :(得分:12)

虽然大多数人盲目地遵循javadoc的建议,但是在非常具体的情况下你想要实际避免使用toString()。例如,我在我的Java代码中使用枚举,但是需要将它们序列化到数据库,然后再返回。如果我使用toString()那么我在技术上会受到其他人指出的被覆盖的行为的影响。

此外,还可以从数据库中反序列化,例如,这应始终使用Java:

MyEnum taco = MyEnum.valueOf(MyEnum.TACO.name());

虽然无法保证:

MyEnum taco = MyEnum.valueOf(MyEnum.TACO.toString());

顺便说一句,我发现Javadoc明确地说'#34;大多数程序员应该"这是非常奇怪的。我发现枚举的toString中只有很少的用例,如果人们使用它作为一个友好的名字"这显然是一个糟糕的用例,因为他们应该使用与i18n更兼容的东西,在大多数情况下,它会使用name()方法。

答案 4 :(得分:4)

name()实际上是枚举的java代码中的文本名称。这意味着它仅限于实际出现在java代码中的字符串,但并非所有可能的字符串都可以在代码中表达。例如,您可能需要一个以数字开头的字符串。 name()将永远无法为您获取该字符串。

答案 5 :(得分:4)

当name()和toString()有意义不同时的一个实际例子是使用单值枚举来定义单例的模式。起初看起来令人惊讶,但很有意义:

enum SingletonComponent {
    INSTANCE(/*..configuration...*/);

    /* ...behavior... */

    @Override
    String toString() {
      return "SingletonComponent"; // better than default "INSTANCE"
    }
}

在这种情况下:

SingletonComponent myComponent = SingletonComponent.INSTANCE;
assertThat(myComponent.name()).isEqualTo("INSTANCE"); // blah
assertThat(myComponent.toString()).isEqualTo("SingletonComponent"); // better

答案 6 :(得分:-1)

您还可以使用类似下面的代码。我使用lombok来避免为吸气剂和构造剂编写一些样板代码。

@AllArgsConstructor
@Getter
public enum RetroDeviceStatus {
    DELIVERED(0,"Delivered"),
    ACCEPTED(1, "Accepted"),
    REJECTED(2, "Rejected"),
    REPAIRED(3, "Repaired");

    private final Integer value;
    private final String stringValue;

    @Override
    public String toString() {
        return this.stringValue;
    }
}