繁体   English   中英

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

[英]Java enum - why use toString instead of name

如果您查看方法name()处的枚举 api,它会说:

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

为什么最好使用toString() 我的意思是当 name() 已经是 final 时 toString 可能会被覆盖。 因此,如果您使用 toString 并且有人覆盖它以返回一个硬编码值,那么您的整个应用程序就会关闭……此外,如果您查看源代码,toString() 方法将准确返回名称,并且仅返回名称。 这是同一件事。

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

  • 如果需要获取用于声明枚举常量的确切名称,则应使用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;
    }
}

当您想要进行比较或将硬编码值用于代码中的某些内部用途时,请使用name()

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

从javadoc(强调我的):

返回对象的字符串表示形式。 通常, toString 方法返回一个“文本表示”此对象的字符串。 结果应该是一个简洁但内容丰富的表示,易于人们阅读 建议所有子类都覆盖此方法。

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

比较MOBILE_PHONE_NUMBERMobile phone number 哪个版本更易读? 我相信第二个。 这是区别: name()总是返回MOBILE_PHONE_NUMBERtoString()可能会被覆盖以返回Mobile phone number

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

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

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

而这不能保证:

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

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

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

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

您也可以使用类似下面的代码。 我使用 lombok 来避免为 getter 和构造函数编写一些样板代码。

@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;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM