Mengapa menggunakan fitur bahasa pemrograman? Alasan kami memiliki bahasa sama sekali adalah untuk
- Pemrogram untuk mengekspresikan algoritma secara efisien dan benar dalam bentuk komputer dapat digunakan.
- Pemelihara untuk memahami algoritma yang telah ditulis orang lain dan membuat perubahan dengan benar .
Enum meningkatkan kemungkinan kebenaran dan keterbacaan tanpa menulis banyak boilerplate. Jika Anda ingin menulis boilerplate, maka Anda dapat "mensimulasikan" enum:
public class Color {
private Color() {} // Prevent others from making colors.
public static final Color RED = new Color();
public static final Color AMBER = new Color();
public static final Color GREEN = new Color();
}
Sekarang Anda dapat menulis:
Color trafficLightColor = Color.RED;
Pelat di atas memiliki efek yang sama dengan
public enum Color { RED, AMBER, GREEN };
Keduanya memberikan tingkat bantuan pemeriksaan yang sama dari kompiler. Boilerplate lebih banyak mengetik. Tetapi menghemat banyak mengetik membuat programmer lebih efisien (lihat 1), jadi ini adalah fitur yang bermanfaat.
Ini bermanfaat untuk setidaknya satu alasan lagi, juga:
Ganti pernyataan
Satu hal yang tidak diberikan static finalsimulasi enum di atas adalah case yang bagus . Untuk tipe enum, Java switch menggunakan tipe variabelnya untuk menyimpulkan lingkup kasus enum, jadi untuk hal di atas Anda hanya perlu mengatakan:switchenum Color
Color color = ... ;
switch (color) {
case RED:
...
break;
}
Perhatikan itu tidak ada Color.REDdalam kasing. Jika Anda tidak menggunakan enum, satu-satunya cara untuk menggunakan jumlah bernama dengan switchsesuatu seperti:
public Class Color {
public static final int RED = 0;
public static final int AMBER = 1;
public static final int GREEN = 2;
}
Tapi sekarang variabel untuk menahan warna harus memiliki tipe int. Kompiler memeriksa enum danstatic final simulasi hilang. Tidak senang.
Kompromi adalah menggunakan anggota bernilai skalar dalam simulasi:
public class Color {
public static final int RED_TAG = 1;
public static final int AMBER_TAG = 2;
public static final int GREEN_TAG = 3;
public final int tag;
private Color(int tag) { this.tag = tag; }
public static final Color RED = new Color(RED_TAG);
public static final Color AMBER = new Color(AMBER_TAG);
public static final Color GREEN = new Color(GREEN_TAG);
}
Sekarang:
Color color = ... ;
switch (color.tag) {
case Color.RED_TAG:
...
break;
}
Tetapi perhatikan, bahkan lebih banyak lagi boilerplate!
Menggunakan enum sebagai singleton
Dari pelat ketel di atas, Anda dapat melihat mengapa enum menyediakan cara untuk mengimplementasikan singleton. Alih-alih menulis:
public class SingletonClass {
public static final void INSTANCE = new SingletonClass();
private SingletonClass() {}
// all the methods and instance data for the class here
}
dan kemudian mengaksesnya dengan
SingletonClass.INSTANCE
kita bisa katakan saja
public enum SingletonClass {
INSTANCE;
// all the methods and instance data for the class here
}
yang memberi kita hal yang sama. Kami bisa lolos dengan ini karena enum Java yang diimplementasikan sebagai kelas penuh dengan hanya sintaksis gula sedikit ditaburi di atas. Lagi-lagi ini kurang matang, tetapi tidak jelas kecuali jika idiomnya sudah Anda kenal. Saya juga tidak suka fakta bahwa Anda mendapatkan berbagai fungsi enum meskipun mereka tidak masuk akal untuk singleton: orddan values, dll. (Sebenarnya ada simulasi yang lebih rumit di mana Color extends Integeritu akan bekerja dengan switch, tapi itu sangat rumit sehingga bahkan lebih rumit jelas menunjukkan mengapa enumitu ide yang lebih baik.)
Keamanan benang
Keamanan utas merupakan masalah potensial hanya saat singleton dibuat malas tanpa penguncian.
public class SingletonClass {
private static SingletonClass INSTANCE;
private SingletonClass() {}
public SingletonClass getInstance() {
if (INSTANCE == null) INSTANCE = new SingletonClass();
return INSTANCE;
}
// all the methods and instance data for the class here
}
Jika banyak utas memanggil getInstancesecara bersamaan saat INSTANCEmasih nol, sejumlah instance dapat dibuat. Ini buruk. Satu-satunya solusi adalah menambahkan synchronizedakses untuk melindungi variabel INSTANCE.
Namun, static finalkode di atas tidak memiliki masalah ini. Ini menciptakan instance dengan penuh semangat pada waktu pemuatan kelas. Pemuatan kelas disinkronkan.
The enumtunggal secara efektif malas karena tidak diinisialisasi sampai digunakan pertama. Inisialisasi Java juga disinkronkan, jadi beberapa utas tidak dapat menginisialisasi lebih dari satu instance INSTANCE. Anda mendapatkan singleton diinisialisasi malas dengan kode yang sangat sedikit. Satu-satunya negatif adalah sintaks yang agak kabur. Anda perlu mengetahui idiom atau memahami sepenuhnya bagaimana pemuatan kelas dan inisialisasi bekerja untuk mengetahui apa yang terjadi.