Java enum - mengapa menggunakan toString alih-alih nama

171

Jika Anda melihat enum api di metode name()itu mengatakan bahwa:

Mengembalikan nama konstanta enum ini, persis seperti yang dinyatakan dalam deklarasi enumnya. Sebagian besar programmer harus menggunakan metode toString sebagai preferensi untuk yang satu ini, karena metode toString dapat mengembalikan nama yang lebih ramah pengguna. Metode ini dirancang terutama untuk digunakan dalam situasi khusus di mana kebenaran tergantung pada mendapatkan nama yang tepat, yang tidak akan berbeda dari rilis ke rilis.

Mengapa lebih baik digunakan toString()? Maksud saya toString dapat diganti ketika nama () sudah final. Jadi jika Anda menggunakan toString dan seseorang menimpanya untuk mengembalikan nilai yang dikodekan, seluruh aplikasi Anda tidak berfungsi ... Juga jika Anda melihat di sumbernya, metode toString () mengembalikan dengan tepat dan hanya nama saja. Itu adalah hal yang sama.

spauny
sumber
4
Anda dapat mengesampingkan toString()dalam enum Anda, tetapi tidak ada orang lain yang dapat memperpanjang dan menimpanya. Anda tidak dapat memperpanjang enum.
Erick G. Hagstrom

Jawaban:

199

Itu benar-benar tergantung pada apa yang ingin Anda lakukan dengan nilai yang dikembalikan:

  • Jika Anda perlu menggunakan nama persis yang digunakan untuk menyatakan konstanta enum, Anda harus menggunakan name()sebagaimana toStringtelah ditimpa
  • Jika Anda ingin mencetak konstanta enum dengan cara yang ramah pengguna, Anda harus menggunakan toStringyang mungkin telah diganti (atau tidak!).

Ketika saya merasa itu mungkin membingungkan, saya memberikan metode yang lebih spesifik getXXX, misalnya:

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;
    }
}
assylias
sumber
1
Ini bisa diterima. Meskipun jika mereka membiarkan enum memiliki kelas dasar hal-hal akan lebih mudah.
ralphgabb
55

Gunakan name()ketika Anda ingin membuat perbandingan atau menggunakan nilai hardcoded untuk beberapa penggunaan internal dalam kode Anda.

Gunakan toString()ketika Anda ingin mempresentasikan informasi kepada pengguna (termasuk pengembang melihat log). Jangan pernah mengandalkan kode Anda untuk toString()memberikan nilai tertentu. Jangan pernah mengujinya terhadap string tertentu. Jika kode Anda rusak ketika seseorang benar mengubah toString()pengembalian, maka itu sudah rusak.

Dari javadoc (penekanan milikku):

Mengembalikan representasi string objek. Secara umum, metode toString mengembalikan string yang "secara teks mewakili" objek ini. Hasilnya harus berupa representasi yang ringkas namun informatif yang mudah dibaca oleh seseorang . Disarankan bahwa semua subclass menimpa metode ini.

Denys Séguret
sumber
23

name()adalah metode "bawaan" dari enum. Itu sudah final dan Anda tidak bisa mengubah implementasinya. Ini mengembalikan nama konstanta enum seperti yang tertulis, misalnya dalam huruf besar, tanpa spasi dll

Bandingkan MOBILE_PHONE_NUMBERdan Mobile phone number. Versi mana yang lebih mudah dibaca? Saya percaya yang kedua. Inilah perbedaannya: name()selalu kembali MOBILE_PHONE_NUMBER, toString()mungkin diganti untuk kembali Mobile phone number.

AlexR
sumber
16
Ini tidak benar !! toString () mengembalikan Mobile phone numberhanya jika Anda menimpanya untuk mengembalikan nilai tersebut. Kalau tidak, itu akan kembaliMOBILE_PHONE_NUMBER
spauny
2
@ spayny, jelas bahwa Anda harus menimpanya toString(). Tangkapannya adalah yang name()tidak bisa diganti karena sudah final.
AlexR
13
@AlexR Anda mungkin perlu memasukkan komentar Anda di atas dalam jawaban untuk membuatnya 100% benar
artfullyContrived
5
Saya setuju dengan @artfullyContrived karena tidak jelas bagi saya sampai saya membaca komentar Anda.
martinatime
13

Sementara kebanyakan orang secara membabi buta mengikuti saran dari javadoc, ada situasi yang sangat spesifik di mana Anda ingin benar-benar menghindari toString (). Sebagai contoh, saya menggunakan enums dalam kode Java saya, tetapi mereka perlu serial ke database, dan kembali lagi. Jika saya terbiasa dengan String () maka secara teknis saya akan mendapatkan perilaku yang ditimpa seperti yang ditunjukkan oleh orang lain.

Selain itu, orang juga dapat menghapus serialisasi dari database, misalnya, ini harus selalu berfungsi di Jawa:

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

Padahal ini tidak dijamin:

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

By the way, saya merasa sangat aneh bagi Javadoc untuk secara eksplisit mengatakan "kebanyakan programmer harus". Saya menemukan sangat sedikit use-case dalam toString of enum, jika orang menggunakan itu untuk "nama yang ramah" itu jelas case-use yang buruk karena mereka harus menggunakan sesuatu yang lebih kompatibel dengan i18n, yang dalam banyak kasus, akan, gunakan metode name ().

coding
sumber
2
Terimakasih telah menjawab. Sudah hampir 5 tahun sejak saya mengajukan pertanyaan ini dan saya belum menggunakan metode toString () untuk enum! 99% dari waktu saya menggunakan enum persis untuk apa yang Anda jelaskan: serialisasi dan deserialising nama enum ke / dari database.
spauny
5

Contoh praktis ketika nama () dan toString () masuk akal untuk berbeda adalah pola di mana enum bernilai tunggal digunakan untuk mendefinisikan singleton. Ini terlihat mengejutkan pada awalnya tetapi masuk akal:

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

    /* ...behavior... */

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

Dalam hal demikian:

SingletonComponent myComponent = SingletonComponent.INSTANCE;
assertThat(myComponent.name()).isEqualTo("INSTANCE"); // blah
assertThat(myComponent.toString()).isEqualTo("SingletonComponent"); // better
Marcin
sumber
Ya, Anda benar ... contoh yang baik adalah Predikat Guava enum
spauny
4

name () secara harfiah adalah nama tekstual dalam kode java enum. Itu berarti terbatas pada string yang benar-benar dapat muncul dalam kode java Anda, tetapi tidak semua string yang diinginkan dapat diungkapkan dalam kode. Misalnya, Anda mungkin memerlukan string yang dimulai dengan angka. name () tidak akan pernah bisa mendapatkan string itu untuk Anda.

Intropi
sumber
-1

Anda juga dapat menggunakan sesuatu seperti kode di bawah ini. Saya menggunakan lombok untuk menghindari penulisan beberapa kode boilerplate untuk getter dan konstruktor.

@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;
    }
}
Kamyar Miremadi
sumber