Pertanyaan Membandingkan anggota Java enum: == atau equals ()?


Saya tahu bahwa enums Java dikompilasi ke kelas dengan konstruktor swasta dan sekelompok anggota statis publik. Ketika membandingkan dua anggota enum yang diberikan, saya selalu menggunakannya .equals(), mis.

public useEnums(SomeEnum a)
{
    if(a.equals(SomeEnum.SOME_ENUM_VALUE))
    {
        ...
    }
    ...
}

Namun, saya baru saja menemukan beberapa kode yang menggunakan operator yang sama == bukannya .equals ():

public useEnums2(SomeEnum a)
{
    if(a == SomeEnum.SOME_ENUM_VALUE)
    {
        ...
    }
    ...
}

Operator mana yang seharusnya saya gunakan?


1418
2017-11-17 17:26


asal


Jawaban:


Keduanya secara teknis benar. Jika Anda melihat kode sumber untuk .equals(), itu hanya menolak ==.

saya menggunakan ==Namun, karena itu akan menjadi nol aman.


1276
2017-11-17 17:29



Bisa == digunakan enum?

Ya: enum memiliki kontrol instan yang ketat yang memungkinkan Anda untuk menggunakannya == untuk membandingkan instance. Berikut jaminan yang diberikan oleh spesifikasi bahasa (penekanan oleh saya):

JLS 8.9 Enums

Tipe enum tidak memiliki contoh selain yang didefinisikan oleh konstanta enumnya.

Ini adalah kesalahan waktu kompilasi untuk mencoba secara eksplisit memberi contoh jenis enum. Itu final clone metode dalam Enum memastikan itu enum konstanta tidak dapat dikloning, dan perlakuan khusus oleh mekanisme serialisasi memastikan bahwa duplikasi contoh tidak pernah dibuat sebagai hasil deserialization. Instansiasi reflektif dari tipe enum dilarang. Bersama-sama, keempat hal ini memastikan bahwa tidak ada contoh dari suatu enum jenis ada di luar yang ditentukan oleh enum konstanta.

Karena hanya ada satu contoh dari masing-masing enum konstan, itu diizinkan untuk menggunakan == operator di tempat equals metode ketika membandingkan dua referensi objek jika diketahui bahwa setidaknya salah satu dari mereka mengacu pada enum konstan. (Itu equals metode dalam Enum adalah final metode yang hanya memanggil super.equals pada argumennya dan mengembalikan hasilnya, sehingga melakukan perbandingan identitas.)

Jaminan ini cukup kuat yang disarankan oleh Josh Bloch, bahwa jika Anda bersikeras untuk menggunakan pola tunggal, cara terbaik untuk menerapkannya adalah dengan menggunakan satu elemen enum (Lihat: Java 2nd Edition efektif, Butir 3: Tegakkan properti tunggal dengan konstruktor pribadi atau tipe enum; juga Keamanan benang di Singleton)


Apa perbedaan antara == dan equals?

Sebagai pengingat, perlu dikatakan bahwa secara umum, == BUKAN alternatif yang layak untuk equals. Namun ketika itu (seperti dengan enum), ada dua perbedaan penting untuk dipertimbangkan:

== tidak pernah melempar NullPointerException

enum Color { BLACK, WHITE };

Color nothing = null;
if (nothing == Color.BLACK);      // runs fine
if (nothing.equals(Color.BLACK)); // throws NullPointerException

== tunduk pada pemeriksaan kompatibilitas jenis pada waktu kompilasi

enum Color { BLACK, WHITE };
enum Chiral { LEFT, RIGHT };

if (Color.BLACK.equals(Chiral.LEFT)); // compiles fine
if (Color.BLACK == Chiral.LEFT);      // DOESN'T COMPILE!!! Incompatible types!

Harus == digunakan saat berlaku?

Bloch secara khusus menyebutkan bahwa kelas-kelas tak berubah yang memiliki kontrol yang tepat atas contoh-contoh mereka dapat menjamin kepada klien mereka itu == dapat digunakan. enum secara spesifik disebutkan untuk dicontohkan.

Butir 1: Pertimbangkan metode pabrik statis daripada konstruktor

[...] memungkinkan kelas yang tidak berubah membuat jaminan bahwa tidak ada dua contoh yang sama: a.equals(b)jika dan hanya jika a==b. Jika kelas membuat jaminan ini, maka kliennya dapat menggunakan == operator, bukan equals(Object) metode, yang dapat menghasilkan peningkatan kinerja. Jenis Enum memberikan jaminan ini.

Untuk meringkas, argumen untuk menggunakan == di enum adalah:

  • Berhasil.
  • Lebih cepat.
  • Lebih aman saat run-time.
  • Lebih aman saat kompilasi.

964
2018-05-30 04:38



Menggunakan == untuk membandingkan dua nilai enum bekerja karena hanya ada satu objek untuk setiap enum konstan.

Di samping catatan, sebenarnya tidak perlu digunakan == untuk menulis kode nol aman jika Anda menulis equals() seperti ini:

public useEnums(SomeEnum a)
{
    if(SomeEnum.SOME_ENUM_VALUE.equals(a))
    {
        ...
    }
    ...
}

Ini adalah praktik terbaik yang dikenal sebagai Bandingkan Konstanta Dari Kiri yang pasti harus Anda ikuti.


72
2017-11-17 17:30



Seperti yang orang lain katakan, keduanya == dan .equals() bekerja dalam banyak 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 dari membandingkan objek dari dua jenis waktu kompilasi yang berbeda juga akan ditemukan oleh FindBugs (dan mungkin oleh Inspeksi waktu kompilasi Eclipse / IntelliJ), sehingga compiler Java menemukan itu tidak menambahkan banyak keamanan ekstra.

Namun:

  1. Fakta bahwa == tidak pernah melempar NPE dalam pikiran saya adalah a kerugian dari ==. Hampir tidak ada kebutuhan enum jenis menjadi null, karena ada keadaan tambahan yang mungkin ingin Anda ekspresikan melalui null hanya bisa ditambahkan ke enum sebagai tambahan. Jika itu tidak terduga null, Saya lebih suka memiliki NPE daripada == diam-diam mengevaluasi ke salah. Oleh karena itu saya tidak setuju dengan itu lebih aman saat run-time pendapat; lebih baik membiasakan tidak pernah membiarkannya enum nilai menjadi @Nullable.
  2. Argumen itu == aku s lebih cepat juga palsu. Dalam kebanyakan kasus, Anda akan menelepon .equals() pada variabel yang mengkompilasi jenis waktu adalah kelas enum, dan dalam kasus-kasus tersebut kompiler dapat mengetahui bahwa ini sama dengan == (karena an enum's equals() metode tidak dapat dikesampingkan) dan dapat mengoptimalkan fungsi pemanggilan. Saya tidak yakin apakah compiler saat ini melakukan ini, tetapi jika tidak, dan ternyata menjadi masalah kinerja di Jawa secara keseluruhan, maka saya lebih suka memperbaiki compiler daripada memiliki programmer Java 100.000 mengubah gaya pemrograman mereka sesuai karakteristik kinerja versi kompilator tertentu.
  3. enums adalah Objek. Untuk semua jenis Objek lainnya, perbandingan standarnya adalah .equals()tidak ==. Saya pikir itu berbahaya untuk membuat pengecualian untuk enums karena Anda mungkin akhirnya tidak sengaja membandingkan Objek dengan == dari pada equals(), terutama jika Anda mem-refactor enum menjadi kelas non-enum. Dalam kasus seperti refactoring, yang Berhasil poin dari atas salah. Untuk meyakinkan diri sendiri bahwa penggunaan == benar, Anda perlu memeriksa apakah nilai yang dimaksud adalah salah satu enum atau primitif; jika itu bukanenumkelas, itu akan salah tetapi mudah untuk dilewatkan karena kode masih akan dikompilasi. Satu-satunya kasus saat penggunaan .equals() akan salah jika nilai-nilai yang dimaksud adalah primitif; dalam hal ini, kode tidak dapat dikompilasi sehingga lebih sulit untuk dilewatkan. Karenanya, .equals() jauh lebih mudah untuk diidentifikasi sebagai benar, dan lebih aman terhadap refactorings masa depan.

Saya benar-benar berpikir bahwa bahasa Jawa seharusnya telah didefinisikan == pada Objek untuk memanggil .equals () pada nilai tangan kiri, dan memperkenalkan operator terpisah untuk identitas objek, tapi itu bukan bagaimana Java didefinisikan.

Singkatnya, saya masih berpikir argumen mendukung penggunaan .equals() untuk enum jenis.


56
2018-02-14 11:59



Berikut ini adalah tes waktu kasar untuk membandingkan keduanya:

import java.util.Date;

public class EnumCompareSpeedTest {

    static enum TestEnum {ONE, TWO, THREE }

    public static void main(String [] args) {

        Date before = new Date();
        int c = 0;

        for(int y=0;y<5;++y) {
            for(int x=0;x<Integer.MAX_VALUE;++x) {
                if(TestEnum.ONE.equals(TestEnum.TWO)) {++c;}
                if(TestEnum.ONE == TestEnum.TWO){++c;}              
            }
        }

        System.out.println(new Date().getTime() - before.getTime());
    }   

}

Komentar IFs satu per satu. Berikut adalah dua perbandingan dari atas dalam kode byte yang dibongkar:

 21  getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
 24  getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
 27  invokevirtual EnumCompareSpeedTest$TestEnum.equals(java.lang.Object) : boolean [28]
 30  ifeq 36

 36  getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19]
 39  getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25]
 42  if_acmpne 48

Yang pertama (sederajat) melakukan panggilan virtual dan menguji pengembalian boolean dari tumpukan. Yang kedua (==) membandingkan alamat objek langsung dari tumpukan. Dalam kasus pertama ada lebih banyak aktivitas.

Saya menjalankan tes ini beberapa kali dengan IFS satu per satu. "==" sedikit lebih cepat.


12
2017-10-14 21:19



Dalam kasus enum keduanya benar dan benar !!


10
2017-11-17 17:28



Saya lebih suka menggunakannya == dari pada equals:

Alasan lain, selain yang lain sudah dibahas di sini, adalah Anda bisa memperkenalkan bug tanpa menyadarinya. Misalkan Anda memiliki enum yang persis sama tetapi dalam pacakges terpisah (tidak umum, tetapi bisa terjadi):

Enum pertama:

package first.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

Enum kedua:

package second.pckg

public enum Category {
    JAZZ,
    ROCK,
    POP,
    POP_ROCK
}

Maka misalkan Anda menggunakan equals like next in item.category yang mana first.pckg.Category tetapi Anda mengimpor enum kedua (second.pckg.Category) bukan yang pertama tanpa menyadarinya:

import second.pckg.Category;
...

Category.JAZZ.equals(item.getCategory())

Jadi Anda akan sembuh false karena adalah enum yang berbeda meskipun Anda berharap benar karena item.getCategory() aku s JAZZ. Dan itu bisa agak sulit untuk dilihat.

Jadi, jika Anda menggunakan operator == Anda akan memiliki kesalahan kompilasi:

operator == tidak dapat diterapkan ke "second.pckg.Category", "first.pckg.Category"

import second.pckg.Category; 
...

Category.JAZZ == item.getCategory() 

10
2018-04-21 06:47



Menggunakan apa pun selain == untuk membandingkan konstanta enum adalah omong kosong. Itu seperti perbandingan class objek dengan equals - jangan lakukan itu!

Namun, ada bug jahat (BugId 6277781) di Sun JDK 6u10 dan sebelumnya yang mungkin menarik untuk alasan historis. Bug ini mencegah penggunaan yang tepat == pada enums deserialized, meskipun ini bisa dibilang agak dari kasus sudut.


4
2017-10-26 20:40



Enums adalah kelas yang mengembalikan satu contoh (seperti tunggal) untuk setiap enumerasi konstan yang dinyatakan oleh public static final field (tidak berubah) jadi itu == Operator dapat digunakan untuk memeriksa kesetaraan mereka daripada menggunakan equals() metode


4
2017-11-07 15:21



Singkatnya, keduanya memiliki kelebihan dan kekurangan.

Di satu sisi, ia memiliki kelebihan untuk digunakan ==, seperti yang dijelaskan dalam jawaban lainnya.

Di sisi lain, jika Anda dengan alasan apapun mengganti enum dengan pendekatan yang berbeda (contoh kelas normal), setelah digunakan == menggigit kamu. (BTDT.)


1
2018-06-04 10:42