Saya tahu bahwa enum Java dikompilasi ke kelas dengan konstruktor pribadi dan sekelompok anggota statis publik. Ketika membandingkan dua anggota enum yang diberikan, saya selalu menggunakan .equals()
, misalnya
public useEnums(SomeEnum a)
{
if(a.equals(SomeEnum.SOME_ENUM_VALUE))
{
...
}
...
}
Namun, saya baru saja menemukan beberapa kode yang menggunakan operator sama dengan ==
.equals ():
public useEnums2(SomeEnum a)
{
if(a == SomeEnum.SOME_ENUM_VALUE)
{
...
}
...
}
Operator mana yang harus saya gunakan?
Jawaban:
Keduanya secara teknis benar. Jika Anda melihat kode sumbernya
.equals()
, itu hanya berlaku untuk==
.Saya menggunakan
==
, bagaimanapun, karena itu akan menjadi nol aman.sumber
.equals()
mengambilnya? Saya tahu saya tidak.Apakah
==
bisa digunakanenum
?Ya: enum memiliki kontrol instans ketat yang memungkinkan Anda gunakan
==
untuk membandingkan instance. Inilah jaminan yang diberikan oleh spesifikasi bahasa (penekanan oleh saya):Jaminan ini cukup kuat yang direkomendasikan Josh Bloch, bahwa jika Anda bersikeras menggunakan pola tunggal, cara terbaik untuk mengimplementasikannya adalah dengan menggunakan elemen tunggal
enum
(lihat: Java Efektif Edisi 2, Butir 3: Terapkan properti singleton dengan konstruktor pribadi atau tipe enum ; juga keamanan Thread di Singleton )Apa perbedaan antara
==
danequals
?Sebagai pengingat, perlu dikatakan bahwa secara umum,
==
BUKAN merupakan alternatif untukequals
. Ketika itu, bagaimanapun (seperti denganenum
), ada dua perbedaan penting yang perlu dipertimbangkan:==
tidak pernah melemparNullPointerException
==
harus mengetik pemeriksaan kompatibilitas pada waktu kompilasiSebaiknya
==
digunakan saat berlaku?Bloch secara khusus menyebutkan bahwa kelas yang tidak dapat diubah yang memiliki kontrol yang tepat atas instance mereka dapat menjamin klien mereka
==
dapat digunakan.enum
secara khusus disebutkan untuk dicontohkan.Untuk meringkas, argumen untuk digunakan
==
padaenum
adalah:sumber
Color nothing = null;
adalah IMHO bug dan harus diperbaiki, enum Anda memiliki dua nilai, bukan tiga ( lihat komentar Tom Hawtin) 4. Lebih aman saat kompilasi : OK, tetapiequals
masih akan kembalifalse
. Pada akhirnya, saya tidak membelinya, saya lebih sukaequals()
untuk keterbacaan (lihat komentar Kevin).foo.equals(bar)
dianggap lebih mudah dibaca daripadafoo == bar
Menggunakan
==
untuk membandingkan dua nilai enum bekerja, karena hanya ada satu objek untuk setiap konstanta enum.Di samping catatan, sebenarnya tidak perlu menggunakan
==
untuk menulis kode null-safe, jika Anda menulisequals()
seperti ini:Ini adalah praktik terbaik yang dikenal sebagai Bandingkan Konstanta Dari Kiri yang harus Anda ikuti.
sumber
.equals()
nilai-nilai string, tetapi saya masih berpikir bahwa itu adalah cara jelek untuk menulis kode null-safe. Saya lebih suka memiliki operator (atau metode, tetapi saya tahu bahwa [objek nol]. Setara tidak akan pernah menjadi null-safe di Jawa karena cara kerja operator titik) yang selalu null-safe, terlepas dari memesannya digunakan. Semantik, operator "sama" harus selalu bolak-balik.?.
), saya akan terus menggunakan praktik ini ketika membandingkan dengan konstanta dan, TBH, saya tidak merasa jelek, mungkin hanya kurang "alami".null
enum biasanya kesalahan. Anda mendapatkan enumerasi untuk semua nilai yang mungkin, dan ini yang lain!@Nullable
, saya menganggap Bandingkan Konstanta Dari Kiri sebagai antipattern karena menyebarkan ambiguitas tentang nilai mana yang bisa atau tidak bisa nol. Jenis Enum seharusnya hampir tidak pernah@Nullable
, jadi nilai nol akan menjadi kesalahan pemrograman; dalam kasus seperti itu, semakin cepat Anda melempar NPE, semakin besar kemungkinan Anda akan menemukan kesalahan pemrograman di mana Anda membiarkannya nol. Jadi "praktik terbaik ... yang harus Anda ikuti" jelas salah dalam hal tipe enum.Seperti yang orang lain katakan, keduanya
==
dan.equals()
bekerja dalam kebanyakan kasus. Kepastian waktu kompilasi bahwa Anda tidak membandingkan jenis Objek yang sama sekali berbeda yang orang lain tunjukkan adalah valid dan bermanfaat, namun jenis bug tertentu membandingkan objek dari dua jenis waktu kompilasi yang berbeda juga akan ditemukan oleh FindBugs (dan mungkin oleh Eclipse / IntelliJ mengkompilasi waktu inspeksi), sehingga Java compiler menemukannya tidak menambah banyak keamanan ekstra.Namun:
==
tidak pernah melempar NPE dalam pikiran saya adalah kelemahan dari==
. Seharusnya hampir tidak pernah ada kebutuhan untukenum
jenisnull
, karena setiap keadaan tambahan yang Anda mungkin ingin ungkapkan vianull
hanya dapat ditambahkanenum
sebagai contoh tambahan. Jika tidak terduganull
, saya lebih suka memiliki NPE daripada==
diam - diam mengevaluasi ke false. Oleh karena itu saya tidak setuju dengan itu lebih aman di opini run-time ; lebih baik untuk membiasakan diri untuk tidak membiarkanenum
nilai-nilai itu terjadi@Nullable
.==
adalah lebih cepat juga palsu. Dalam kebanyakan kasus, Anda akan menelepon.equals()
pada variabel yang tipe waktu kompilasi adalah kelas enum, dan dalam kasus-kasus compiler dapat tahu bahwa ini adalah sama dengan==
(karena seorangenum
'sequals()
metode tidak bisa ditimpa) dan dapat mengoptimalkan fungsi panggilan jauh. Saya tidak yakin apakah kompiler saat ini melakukan ini, tetapi jika tidak, dan ternyata menjadi masalah kinerja di Jawa secara keseluruhan, maka saya lebih suka memperbaiki kompiler daripada memiliki 100.000 programmer Java mengubah gaya pemrograman mereka sesuai karakteristik kinerja versi kompiler tertentu.enums
adalah Objects. Untuk semua jenis Objek lainnya, perbandingan standarnya adalah.equals()
, bukan==
. Saya pikir itu berbahaya untuk membuat pengecualianenums
karena Anda mungkin akhirnya secara tidak sengaja membandingkan Objek dengan,==
bukanequals()
, terutama jika Anda mereformasi suatuenum
ke dalam kelas non-enum. Dalam hal refactoring seperti itu, titik kerjanya dari atas salah. Untuk meyakinkan diri sendiri bahwa penggunaan kata==
benar, Anda perlu memeriksa apakah nilai yang dipermasalahkan adalahenum
primitif; jika itu bukanenum
kelas, itu akan salah tetapi mudah dilewatkan karena kode masih akan dikompilasi. Satu-satunya kasus ketika penggunaan.equals()
yang salah adalah jika nilai-nilai tersebut primitif; dalam hal ini, kode tidak akan dikompilasi sehingga lebih sulit untuk dilewatkan. Oleh karena itu,.equals()
lebih mudah untuk mengidentifikasi sebagai yang benar, dan lebih aman terhadap refactoring di masa depan.Saya benar-benar berpikir bahwa bahasa Jawa seharusnya telah mendefinisikan == pada Objek untuk memanggil .equals () pada nilai sebelah kiri, dan memperkenalkan operator terpisah untuk identitas objek, tetapi bukan itu yang didefinisikan Java.
Singkatnya, saya masih berpikir argumennya mendukung penggunaan
.equals()
untukenum
tipe.sumber
enum
sebagaiswitch
target sehingga mereka agak istimewa.String
s juga agak istimewa.Saya lebih suka menggunakan
==
daripadaequals
:Alasan lain, selain yang sudah dibahas di sini, adalah Anda bisa memperkenalkan bug tanpa menyadarinya. Misalkan Anda memiliki enum ini yang persis sama tetapi dalam pacakges terpisah (itu tidak umum, tetapi itu bisa terjadi):
Enum pertama :
Enum kedua:
Kemudian misalkan Anda menggunakan equals seperti berikutnya dalam
item.category
yangfirst.pckg.Category
tetapi Anda mengimpor enum kedua (second.pckg.Category
) bukan yang pertama tanpa menyadarinya:Jadi Anda akan mendapatkan allways
false
karena merupakan enum berbeda walaupun Anda harapkan karena benaritem.getCategory()
adalahJAZZ
. Dan itu bisa agak sulit dilihat.Jadi, jika Anda menggunakan operator,
==
Anda akan memiliki kesalahan kompilasi:sumber
Berikut ini adalah tes waktu kasar untuk membandingkan keduanya:
Komentari IFs satu per satu. Berikut adalah dua perbandingan dari atas dalam byte-code yang dibongkar:
Yang pertama (sama dengan) melakukan panggilan virtual dan menguji boolean kembali dari tumpukan. Yang kedua (==) membandingkan alamat objek secara langsung dari tumpukan. Dalam kasus pertama ada lebih banyak aktivitas.
Saya menjalankan tes ini beberapa kali dengan kedua IF satu per satu. "==" sedikit lebih cepat.
sumber
Dalam hal enum keduanya benar dan benar !!
sumber
tl; dr
Pilihan lain adalah
Objects.equals
metode utilitas.Objects.equals
untuk null-safetyOpsi ketiga adalah
equals
metode statis yang ditemukan padaObjects
kelas utilitas yang ditambahkan ke Java 7 dan yang lebih baru.Contoh
Berikut ini contoh menggunakan
Month
enum.Manfaat
Saya menemukan beberapa manfaat untuk metode ini:
true
false
NullPointerException
Bagaimana itu bekerja
Logika apa yang digunakan
Objects.equals
?Lihat sendiri, dari kode sumber Java 10 dari OpenJDK :
sumber
Menggunakan apa pun selain
==
untuk membandingkan konstanta enum adalah omong kosong. Ini seperti membandingkanclass
objek denganequals
- jangan lakukan itu!Namun, ada bug jahat (BugID 6277781 ) di Sun JDK 6u10 dan sebelumnya yang mungkin menarik karena alasan historis. Bug ini mencegah penggunaan yang tepat
==
pada enum deserialized, meskipun ini bisa dibilang agak sudut kasus.sumber
Enum adalah kelas yang mengembalikan satu instance (seperti lajang) untuk setiap konstanta enumerasi yang dideklarasikan oleh
public static final field
(immutable) sehingga==
operator dapat digunakan untuk memeriksa kesetaraan mereka daripada menggunakanequals()
metodesumber
Alasan enum bekerja dengan mudah dengan == adalah karena setiap instance yang didefinisikan juga merupakan singleton. Jadi perbandingan identitas menggunakan == akan selalu berhasil.
Tetapi menggunakan == karena ini bekerja dengan enums berarti semua kode Anda erat dengan penggunaan enum itu.
Misalnya: Enums dapat mengimplementasikan antarmuka. Misalkan Anda saat ini menggunakan enum yang mengimplementasikan Interface1. Jika nanti, seseorang mengubahnya atau memperkenalkan Impl1 kelas baru sebagai implementasi dari antarmuka yang sama. Kemudian, jika Anda mulai menggunakan instans Impl1, Anda akan memiliki banyak kode untuk diubah dan diuji karena penggunaan == sebelumnya.
Oleh karena itu, yang terbaik adalah mengikuti apa yang dianggap sebagai praktik yang baik kecuali jika ada keuntungan yang dapat dibenarkan.
sumber
Salah satu aturan Sonar adalah
Enum values should be compared with "=="
. Alasannya adalah sebagai berikut:Last but not least,
==
pada enum bisa dibilang lebih mudah dibaca (kurang verbose) daripadaequals()
.sumber
Singkatnya, keduanya memiliki pro dan kontra.
Di satu sisi, ia memiliki kelebihan untuk digunakan
==
, seperti yang dijelaskan dalam jawaban lain.Di sisi lain, jika Anda dengan alasan apa pun mengganti enum dengan pendekatan yang berbeda (instance kelas normal), setelah menggunakan
==
menggigit Anda. (BTDT.)sumber
Saya ingin melengkapi jawaban polygenelubricants:
Saya pribadi lebih suka sama dengan (). Tapi itu memeriksa kompatibilitas jenis. Yang menurut saya merupakan batasan penting.
Untuk melakukan pemeriksaan kompatibilitas jenis pada waktu kompilasi, deklarasikan dan gunakan fungsi kustom di enum Anda.
Dengan ini, Anda mendapatkan semua keuntungan dari kedua solusi: perlindungan NPE, kode mudah dibaca dan ketik kompatibilitas kompatibilitas pada waktu kompilasi.
Saya juga merekomendasikan untuk menambahkan nilai UNDEFINED untuk enum.
sumber
==
? Dengan==
Anda mendapatkan perlindungan NPE, kode yang mudah dibaca, dan kompilasi pengecekan kompatibilitas jenis waktu, dan Anda mendapatkan semua itu tanpa menulis metode khusus yang sama dengan kustom.UNDEFINED
nilai adalah mungkin ide yang baik. Tentu saja, di Java 8 Anda akan menggunakanOptional
gantinya.