Selama fase pengembangan, ada variabel tertentu yang perlu diperbaiki dalam menjalankan yang sama, tetapi mungkin perlu dimodifikasi dari waktu ke waktu. Misalnya a boolean
ke mode debug mode, jadi kami melakukan hal-hal dalam program yang biasanya tidak kami lakukan.
Apakah gaya buruk mengandung nilai-nilai ini dalam konstanta, yaitu final static int CONSTANT = 0
di Jawa? Saya tahu bahwa konstanta tetap sama selama waktu berjalan, tetapi apakah itu juga seharusnya sama selama pengembangan keseluruhan, kecuali untuk perubahan yang tidak direncanakan, tentu saja?
Saya mencari pertanyaan serupa, tetapi tidak menemukan apa pun yang cocok dengan saya.
final
memberi Anda jaminan yang diberlakukan kompiler bahwa program tidak akan mengubah nilai. Saya tidak akan membuang itu hanya karena programmer mungkin ingin memodifikasi nilai yang ditetapkan dalam kode sumber.gravity
pertengahan pertandingan / lari. Mereka tidak selalu berarti,gravity
sama di setiap planet ... Yang mengatakan, solusi yang sehat adalah dengan membuatgravity
konstanta, tetapi menariknya dariplanet
file atau database pada awal ruang lingkup yang relevan.Jawaban:
Di Jawa, konstanta akhir statis dapat disalin, oleh kompiler, sebagai nilainya, ke dalam kode yang menggunakannya . Sebagai akibatnya, jika Anda merilis versi baru dari kode Anda, dan ada beberapa dependensi hilir yang telah menggunakan konstanta, konstanta dalam kode itu tidak akan diperbarui kecuali kode downstream dikompilasi ulang. Ini bisa menjadi masalah jika mereka menggunakan konstanta itu dengan kode yang mengharapkan nilai baru, meskipun kode sumbernya benar, kode binernya tidak.
Ini adalah kutil dalam desain Java, karena ini adalah salah satu dari sedikit kasus (mungkin satu-satunya kasus) di mana kompatibilitas sumber dan kompatibilitas biner tidak sama. Kecuali untuk kasus ini, Anda dapat menukar ketergantungan dengan versi API-kompatibel baru tanpa pengguna ketergantungan harus melakukan kompilasi ulang. Jelas ini sangat penting mengingat cara di mana dependensi Java umumnya dikelola.
Yang memperburuk masalah adalah bahwa kode hanya akan diam-diam melakukan hal yang salah daripada menghasilkan kesalahan yang bermanfaat. Jika Anda mengganti ketergantungan dengan versi dengan definisi metode atau kelas yang tidak kompatibel, Anda akan mendapatkan kesalahan classloader atau doa, yang setidaknya memberikan petunjuk yang baik tentang apa masalahnya. Kecuali Anda telah mengubah jenis nilai, masalah ini hanya akan muncul sebagai perilaku runtime misterius.
Lebih menjengkelkan adalah bahwa JVM hari ini dapat dengan mudah inline semua konstanta pada saat runtime tanpa penalti kinerja (selain dari kebutuhan untuk memuat kelas mendefinisikan konstanta, yang mungkin sedang dimuat pula), sayangnya semantik tanggal bahasa dari hari-hari sebelum JIT . Dan mereka tidak dapat mengubah bahasa karena kode yang dikompilasi dengan kompiler sebelumnya tidak akan benar. Kompatibilitas bugward menyerang lagi.
Karena semua ini beberapa orang menyarankan untuk tidak mengubah nilai akhir statis sama sekali. Untuk perpustakaan yang mungkin didistribusikan secara luas dan diperbarui dengan cara yang tidak diketahui pada waktu yang tidak diketahui, ini adalah praktik yang baik.
Dalam kode Anda sendiri, terutama di bagian atas hierarki dependensi, Anda mungkin akan lolos begitu saja. Tetapi dalam kasus ini, pertimbangkan apakah Anda benar-benar membutuhkan konstanta untuk publik (atau dilindungi). Jika konstanta hanya visibilitas paket, itu wajar, tergantung pada keadaan dan standar kode Anda, bahwa seluruh paket akan selalu dikompilasi ulang sekaligus, dan masalahnya kemudian hilang. Jika konstanta bersifat pribadi, Anda tidak memiliki masalah dan dapat mengubahnya kapan pun Anda mau.
sumber
Apa pun dalam kode sumber Anda, termasuk
const
konstanta global yang dinyatakan, dapat berubah sewaktu-waktu dengan rilis baru perangkat lunak Anda.Kata kunci
const
(ataufinal
di Jawa) ada di sana untuk memberi sinyal kepada kompiler bahwa variabel ini tidak akan berubah ketika program ini sedang berjalan . Tidak ada lagi. Jika Anda ingin mengirim pesan ke pengelola berikutnya, gunakan komentar dalam sumber, untuk itulah mereka ada.Merupakan cara yang lebih baik untuk berkomunikasi dengan diri masa depan Anda.
sumber
TaxRate
menjadipublic
membuatku gugup. Saya ingin tahu pasti bahwa hanya departemen penjualan yang terpengaruh oleh perubahan ini dan bukan juga pemasok kami yang mengenakan pajak kepada kami. Siapa yang tahu apa yang terjadi di basis kode sejak komentar itu ditulis.public const
bidang hanya boleh digunakan untuk hal-hal yang tidak akan pernah berubah, seperti Math.pi. Jika Anda membuat perpustakaan, hal-hal yang mungkin berubah selama pengembangan atau dengan versi baru seharusnyapublic static readonly
, sehingga tidak menyebabkan masalah dengan pengguna perpustakaan Anda.Kita perlu membedakan dua aspek konstanta:
Dan kemudian ada jenis ketiga terkait: variabel yang nilainya tidak berubah, yaitu nama untuk nilai. Perbedaan antara variabel yang tidak berubah ini dan konstanta adalah ketika nilai ditentukan / ditugaskan / diinisialisasi: variabel diinisialisasi pada saat runtime, tetapi nilai konstanta diketahui selama pengembangan. Perbedaan ini agak berlumpur karena nilai dapat diketahui selama pengembangan tetapi sebenarnya hanya dibuat selama inisialisasi.
Tetapi jika nilai konstanta diketahui pada waktu kompilasi, maka kompiler dapat melakukan perhitungan dengan nilai itu. Sebagai contoh, bahasa Jawa memiliki konsep ekspresi konstan . Ekspresi konstan adalah ekspresi apa pun yang hanya terdiri dari literal primitif atau string, operasi pada ekspresi konstan (seperti casting, penambahan, penggabungan string), dan variabel konstan. [ JLS §15.28 ] Variabel konstan adalah
final
variabel yang diinisialisasi dengan ekspresi konstan. [JLS §4.12.4] Jadi untuk Java, ini adalah konstanta waktu kompilasi:Ini menjadi menarik ketika variabel konstan digunakan dalam beberapa unit kompilasi, dan kemudian deklarasi diubah. Mempertimbangkan:
A.java
:B.java
:Sekarang ketika kita mengkompilasi file-file ini
B.class
bytecode akan mendeklarasikan sebuah fieldY = 9
karenaB.Y
merupakan variabel konstan.Tetapi ketika kita mengubah
A.X
variabel ke nilai yang berbeda (katakanlahX = 0
) dan hanya mengkompilasi ulangA.java
file, makaB.Y
masih mengacu pada nilai yang lama. KeadaanA.X = 0, B.Y = 9
ini tidak konsisten dengan deklarasi dalam kode sumber. Selamat men-debug!Ini tidak berarti bahwa konstanta tidak boleh diubah. Konstanta secara definitif lebih baik daripada angka ajaib yang muncul tanpa penjelasan dalam kode sumber. Namun, yang nilai dari konstanta publik merupakan bagian dari API publik Anda . Ini tidak khusus untuk Java, tetapi juga terjadi di C ++ dan bahasa lain yang menampilkan unit kompilasi terpisah. Jika Anda mengubah nilai-nilai ini, Anda harus mengkompilasi ulang semua kode dependen, yaitu melakukan kompilasi bersih.
Tergantung pada sifat konstanta, mereka mungkin menyebabkan asumsi yang salah oleh pengembang. Jika nilai-nilai ini diubah, mereka dapat memicu bug. Sebagai contoh, satu set konstanta dapat dipilih sehingga mereka membentuk pola bit tertentu, misalnya
public static final int R = 4, W = 2, X = 1
. Jika ini diubah untuk membentuk struktur yang berbeda sepertiR = 0, W = 1, X = 2
maka kode yang ada sepertiboolean canRead = perms & R
menjadi salah. Dan pikirkan kesenangan yang akan terjadi kemudianInteger.MAX_VALUE
berubah! Tidak ada perbaikan di sini, hanya penting untuk diingat bahwa nilai beberapa konstanta benar-benar penting dan tidak dapat diubah secara sederhana.Tetapi untuk mayoritas konstanta yang mengubahnya akan baik-baik saja selama pembatasan di atas dipertimbangkan. Konstanta aman untuk diubah ketika maknanya, bukan nilai spesifik yang penting. Ini adalah contoh kasus untuk merdu seperti
BORDER_WIDTH = 2
atauTIMEOUT = 60; // seconds
atau template sepertiAPI_ENDPOINT = "https://api.example.com/v2/"
- meskipun bisa dibilang beberapa atau semua dari mereka harus ditentukan dalam file konfigurasi daripada kode.sumber
Konstanta hanya dijamin konstan untuk umur runtime aplikasi . Selama itu benar, tidak ada alasan untuk tidak memanfaatkan fitur bahasa. Anda hanya perlu tahu apa konsekuensinya untuk menggunakan flag konstan vs compiler untuk tujuan yang sama:
Setelah mempertahankan aplikasi yang akan mengaktifkan menggambar kotak pembatas untuk bentuk sehingga kami bisa men-debug bagaimana mereka digambar, kami mengalami masalah. Setelah refactoring, semua kode yang dimatikan oleh flag compiler tidak akan dikompilasi. Setelah itu, kami sengaja mengubah flag compiler kami menjadi konstanta aplikasi.
Saya mengatakan itu untuk menunjukkan bahwa ada pertukaran. Bobot beberapa booleans tidak akan membuat aplikasi kehabisan memori atau mengambil terlalu banyak ruang. Itu mungkin tidak benar jika konstanta Anda benar-benar objek besar yang pada dasarnya memiliki pegangan untuk semua yang ada dalam kode Anda. Jika tidak hati-hati menghapus semua referensi yang dipegangnya pada suatu objek setelah tidak diperlukan lagi, maka objek Anda mungkin menjadi sumber kebocoran memori.
Saya bukan penggemar pernyataan selimut sederhana, tetapi secara umum kolega senior Anda benar. Jika sesuatu cenderung berubah sering, itu mungkin harus menjadi item yang dapat dikonfigurasi. Misalnya, Anda mungkin bisa meyakinkan kolega Anda untuk konstanta
IsInDebugMode = true
ketika Anda ingin melindungi beberapa kode dari kerusakan. Namun, beberapa hal mungkin perlu diubah lebih sering daripada Anda merilis aplikasi. Jika demikian, Anda perlu cara mengubah nilai itu pada waktu yang tepat. Anda dapat mengambil contoh aTaxRate = .065
. Itu mungkin benar pada saat Anda mengkompilasi kode Anda, tetapi karena undang-undang baru itu dapat berubah sebelum Anda merilis versi berikutnya dari aplikasi Anda. Itu adalah sesuatu yang perlu diperbarui baik dari beberapa mekanisme penyimpanan (seperti file atau database)sumber
#ifdef
s? Karena ini didasarkan pada substitusi teks dari kode sumber, mereka bukan bagian dari semantik bahasa pemrograman. Perhatikan bahwa Java tidak memiliki preprosesor.#ifdef
bendera. Meskipun mereka bukan bagian dari semantik C, mereka adalah bagian dari C #. Saya menulis untuk konteks agnostisisme bahasa yang lebih besar.Petunjuk
const
,#define
ataufinal
petunjuk kompiler (perhatikan bahwa#define
sebenarnya bukan petunjuk, ini adalah petunjuk makro dan jauh lebih kuat). Ini menunjukkan bahwa nilai tidak akan berubah selama pelaksanaan suatu program dan berbagai optimasi dapat dilakukan.Namun, sebagai petunjuk kompiler, kompiler melakukan hal-hal yang mungkin tidak selalu diharapkan oleh programmer. Secara khusus, javac akan inline
static final int FOO = 42;
sehingga di mana saja yangFOO
digunakan, sebenarnya dikompilasi kode byte akan membaca42
.Ini tidak terlalu mengejutkan sampai seseorang mengubah nilainya tanpa mengkompilasi ulang unit kompilasi lainnya (file .java) - dan
42
sisa - sisa dalam kode byte (lihat apakah mungkin untuk menonaktifkan inlining javac tentang variabel akhir statis? ).Membuat sesuatu
static final
berarti bahwa itu adalah itu dan selamanya lebih dari itu dan mengubahnya itu adalah Kesepakatan yang Sangat Besar - terutama jika itu bukan apa-apaprivate
.Konstanta untuk hal-hal seperti
final static int ZERO = 0
bukan masalah.final static double TAX_RATE = 0.55
(Selain karena uang dan dobel itu buruk dan harus menggunakan BigDecimal, tapi itu bukan primitif dan karenanya tidak diuraikan) adalah masalah dan harus diperiksa dengan hati-hati untuk penggunaannya.sumber
is a problem and should be examined with great care for where it is used.
Mengapa ini menjadi masalah?Seperti namanya, konstanta tidak boleh berubah selama runtime dan menurut saya konstanta didefinisikan tidak berubah untuk jangka panjang (Anda dapat melihat pertanyaan SO ini untuk informasi lebih lanjut.
Ketika datang ke kebutuhan flag (misalnya untuk mode pengembangan) Anda harus menggunakan file konfigurasi atau parameter startup (banyak IDE mendukung konfigurasi parameter startup pada per-proyek-basis; lihat dokumentasi yang relevan) untuk mengaktifkan mode ini - dengan cara ini Anda menjaga fleksibilitas untuk menggunakan mode seperti itu dan Anda tidak bisa lupa untuk mengubahnya setiap kali kode menjadi produktif.
sumber
Mampu diubah antara proses adalah salah satu poin paling penting dalam mendefinisikan konstanta dalam kode sumber Anda!
Konstanta memberi Anda lokasi yang terdefinisi dengan baik dan terdokumentasi (dalam arti tertentu) untuk mengubah nilai kapan pun Anda perlu selama masa hidup kode sumber Anda. Ini juga merupakan janji bahwa mengubah konstanta di lokasi ini akan benar-benar mengubah semua kejadian apa pun artinya.
Sebagai contoh yang merugikan: tidak masuk akal untuk memiliki konstanta
TRUE
yang dievaluasitrue
dalam bahasa yang benar-benar memilikitrue
kata kunci. Anda tidak akan pernah, tidak pernah sekalipun, menyatakanTRUE=false
kecuali sebagai lelucon kejam.Tentu saja ada kegunaan lain dari konstanta, misalnya kode shortening (
CO_NAME = 'My Great World Unique ACME Company'
), menghindari duplikasi (PI=3.141
), pengaturan konvensi (TRUE=1
) atau apa pun, tetapi memiliki posisi yang ditentukan untuk mengubah konstanta tentu saja merupakan salah satu yang paling menonjol.sumber