Java列挙型-名前の代わりにtoStringを使用する理由


171

メソッドname()でenum apiを見ると、次のように書かれています。

enum宣言で宣言されているとおりに、このenum定数の名前を返します。toStringメソッドはよりわかりやすい名前を返す可能性があるため、ほとんどのプログラマは、これよりもtoStringメソッドを使用する必要があります。このメソッドは、正確さが正確な名前の取得に依存する特殊な状況での使用を主な目的として設計されており、リリースごとに異なることはありません。

なぜ使用するのが良いtoString()ですか?つまり、name()がすでにfinalである場合、toStringがオーバーライドされる可能性があります。したがって、toStringを使用し、誰かがそれをオーバーライドしてハードコードされた値を返す場合、アプリケーション全体がダウンします...また、ソースを見ると、toString()メソッドは正確に名前のみを返します。同じことです。


4
toString()enumでオーバーライドできますが、それを拡張してオーバーライドすることはできません。列挙型を拡張することはできません。
エリックG.ハグストロム2016年

回答:


198

それは本当に戻り値で何をしたいかに依存します:

  • あなたが列挙型定数を宣言するために使用される正確な名前を取得する必要がある場合は、使用する必要がありますname()ようtoStringにオーバーライドされていたかもしれません
  • enum定数をユーザーフレンドリーな方法で出力する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
これは許容範囲です。列挙型に基本クラスを持たせると、もっと簡単になります。
ralphgabb 2018年

55

使用name()あなたが比較を行うか、あなたのコード内のいくつかの内部使用のためにハードコードされた値を使用します。

toString()ユーザー(ログを見る開発者を含む)に情報を提示する場合に使用します。toString()特定の値を与えることをコードに依存しないでください。特定の文字列に対してはテストしないでください。誰かがtoString()戻り値を正しく変更したときにコードが壊れた場合、そのコードはすでに壊れています。

javadoc(強調鉱山)から:

オブジェクトの文字列表現を返します。一般に、toStringメソッドは、このオブジェクトを「テキストで表す」文字列を返します。結果は、簡潔でありながら有益な表現で、人が読みやすいものにする必要がありますすべてのサブクラスがこのメソッドをオーバーライドすることをお勧めします。


23

name()の「組み込み」メソッドですenum。これは最終的なものであり、実装を変更することはできません。大文字で、スペースなしなど、記述されている列挙定数の名前を返します。

比較MOBILE_PHONE_NUMBERMobile phone number。より読みやすいバージョンはどれですか?私は2番目のものを信じています。これが違いです:name()常にリターンはMOBILE_PHONE_NUMBERtoString()リターンにオーバーライドすることができますMobile phone number


16
これは正しくありません!! toString()はMobile phone number、オーバーライドしてそのような値を返す場合にのみ戻ります。それ以外の場合は返されますMOBILE_PHONE_NUMBER
スパニーが

2
@spayny、オーバーライドする必要があることは明らかですtoString()。キャッチは、name()最終的なものであるため、オーバーライドできないことです。
AlexR

13
@AlexR 100%正確にするために、上記のコメントを回答に組み込む必要がある場合があります
artfullyContrived

5
@artfullyContrivedに同意します。あなたのコメントを読むまではわかりませんでした。
martinatime 2014

13

ほとんどの人は盲目的にjavadocのアドバイスに従いますが、toString()を実際に避けたい非常に特殊な状況があります。たとえば、Javaコードで列挙型を使用していますが、それらをデータベースにシリアル化し、再度戻す必要があります。toString()を使用した場合、他の人が指摘したように、オーバーライドされた動作を技術的に取得する必要があります。

さらに、データベースからデシリアライズすることもできます。たとえば、これは常にJavaで動作するはずです。

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

これは保証されていませんが:

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

ちなみに、Javadocが「ほとんどのプログラマーがすべき」と明示的に言うのは非常に奇妙です。列挙型のtoStringのユースケースはほとんど見つかりません。人々がi18nと互換性のあるものを使用する必要があるため、明らかに「フレンドリーな名前」に使用している場合、これは明らかに貧弱なユースケースであり、ほとんどの場合、 name()メソッドを使用します。


2
回答ありがとうございます。この質問をしてから約5年になりますが、列挙型にtoString()メソッドをまだ使用していません。99%は、あなたが説明したとおりに列挙型を正確に使用します:列挙型名のデータベースへの/からの直列化および逆シリアル化。
スパニー

5

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

ええ、あなたは正しいです...良い例はグアバの列挙型述語
スパニー

4

name()は、文字通り、列挙型のJavaコード内のテキスト名です。つまり、Javaコードに実際に表示できる文字列に制限されますが、望ましい文字列がすべてコードで表現できるわけではありません。たとえば、数字で始まる文字列が必要になる場合があります。name()がその文字列を取得することはできません。


-1

以下のコードのようなものを使用することもできます。ゲッターとコンストラクターのボイラープレートコードの一部を書くのを避けるために、ロンボクを使用しました。

@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;
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.