Mengapa kata kunci 'final' hanya digunakan sedikit di industri? [Tutup]

14

Karena saya menemukan kekuatan finalkata kunci di Jawa beberapa tahun yang lalu, itu membantu saya untuk membuat kode saya lebih mudah dibaca, karena orang dapat dengan mudah melihat apa yang hanya variabel baca-saja. Ini juga dapat memberikan sedikit dorongan kepada JIT, dan meskipun itu sangat terbatas, JIT tidak dapat membahayakan, terutama ketika menargetkan perangkat yang disematkan seperti platform android.

Tetapi lebih dari segalanya, itu berkontribusi untuk membuat desain lebih kuat untuk perubahan, dan membimbing committer lain ketika mereka perlu memodifikasi basis kode.

Namun, saat menelusuri beberapa kode sumber JDK, saya tidak pernah menemukan kata kunci ini, baik untuk kelas, metode, atau variabel. Hal yang sama berlaku untuk berbagai sistem yang harus saya ulas.

Apakah ada alasan? Apakah ini merupakan paradigma desain yang umum untuk membiarkan semuanya berubah dari dalam?

Aurelien Ribon
sumber
dalam optimasi mikro, pengaturan finalbidang memiliki semantik yang sama dengan menulis volatilebidang, dan kemudian membacanya nanti harus memiliki semantik baca yang mudah berubah, ini tidak selalu seperti yang Anda inginkan
ratchet freak
5
@ scratchet: Saya pikir ini lebih tentang membuat kelas Anda tidak berubah, seperti dalam pemrograman fungsional.
Jonas
@Kwebble: Mungkin yang lebih penting, instance String individual tidak dapat diubah.
MatrixFrog

Jawaban:

9

Saya menduga bahwa alasan Anda tidak melihatnya adalah karena JDK dirancang untuk diperpanjang (itu adalah dasar dari mana semua program Anda dibangun). Tidak jarang sama sekali bagi kode aplikasi untuk memanfaatkannya. Saya juga tidak akan berharap untuk melihat banyak dalam kode perpustakaan baik (karena perpustakaan sering dirancang untuk ekstensi juga).

Coba lihat beberapa proyek open source yang bagus dan saya pikir Anda akan menemukan lebih banyak.

Berbeda dengan apa yang Anda lihat di Jawa, di dunia .NET, saya telah mendengar argumen berkali-kali bahwa klase seharusnya sealed(mirip dengan final diterapkan pada kelas) secara default, dan bahwa pengembang harus secara eksplisit melepaskan segel Itu.

Steven Evers
sumber
2
Saya bahkan merujuk ke banyak anggota pribadi atau yang dilindungi dari beberapa kelas JDK yang jelas-jelas "menelurkan sekali, tidak pernah menimpa" variabel objek. Khususnya dalam paket swing. Itu adalah kandidat yang sempurna untuk 'final', karena ada penggantian dengan pointer nol akan menyebabkan kesalahan saat menggunakan komponen.
Aurelien Ribon
1
@ Aurélien: Jika itu membuat Anda merasa lebih baik, banyak kelas di .NET Framework disegel, banyak yang mengkhawatirkan beberapa pengguna yang ingin memperluas kelas kerangka kerja dengan fungsi mereka sendiri. Namun, batasan ini dapat dikurangi sedikit dengan menggunakan Metode Ekstensi.
Robert Harvey
1
Saya pikir ini lebih tentang kekekalan daripada menghindari ekstensi. Dengan kata lain penggunaan finalpada bidang dan bukan pada metode. Kelas yang tidak dapat berubah juga dapat dirancang untuk diperpanjang.
Jonas
15

Masalah dengan menggunakan finaluntuk menyampaikan bahwa sesuatu hanya-baca adalah bahwa itu hanya benar-benar berfungsi untuk tipe primitif seperti int, chardll. Semua objek di Jawa sebenarnya disebut menggunakan pointer (jenis). Akibatnya, saat Anda menggunakan finalkata kunci pada objek, Anda hanya mengatakan bahwa referensi tersebut hanya baca, objek itu sendiri masih bisa berubah.

Itu mungkin telah digunakan lebih banyak jika itu benar-benar membuat objek hanya-baca. Dalam C ++ itulah yang constberfungsi dan hasilnya kata kunci ini jauh lebih berguna dan banyak digunakan.

Satu tempat saya sangat menggunakan finalkata kunci adalah dengan parameter untuk menghindari kebingungan yang dibuat oleh hal-hal seperti ini:

public void someMethod(FancyObject myObject) {
    myObject = new FancyObject();
    myObject.setProperty(7);
}
...
public static void main(final String[] args) {
    ...
    FancyObject myObject = new FancyObject();
    someOtherObject.someMethod(myObject);
    myObject.getProperty(); // Not 7!
}

Dalam contoh ini tampak jelas mengapa ini tidak berhasil tetapi jika someMethod(FancyObject)kebingungan besar dan rumit dapat terjadi. Kenapa tidak menghindarinya?

Ini juga merupakan bagian dari standar pengkodean Sun (atau Oracle sekarang saya kira).

Gyan alias Gary Buyn
sumber
1
Jika ada lebih banyak penggunaan finaldi kelas Java API, sebagian besar objek telah berubah seperti dengan banyak perpustakaan Scala. Kemudian membuat bidang objek finalmembuat kelas tidak berubah dalam banyak kasus. Desain ini sudah digunakan di BigDecimaldan String.
Jonas
@Jonas Saya membaca pertanyaan untuk lebih lanjut tentang poin 4 dalam jawaban schmmd karena dia berkata "karena orang dapat dengan mudah melihat apa yang hanya variabel read-only" dan menjawab sesuai. Mungkin saya harus memasukkan asumsi itu dalam jawabannya.
Gyan alias Gary Buyn
Ingatlah bahwa ada waktu ketika Anda ingin menetapkan kembali parameter. Sebagai contoh adalah memangkas parameter string.
Steve Kuo
@Steve Saya biasanya membuat variabel baru untuk ditugaskan dalam situasi itu.
Gyan alias Gary Buyn
1
@Gary, bagi saya setidaknya, sangat jarang bug / kebingungan disebabkan oleh penugasan ulang parameter. Saya lebih suka memiliki kode bebas kekacauan dan menerima kesempatan jauh untuk menetapkan kembali parameter yang menyebabkan bug. Berhati-hatilah saat menulis / memodifikasi kode.
Steve Kuo
4

Saya setuju bahwa final kata kunci meningkatkan keterbacaan. Itu membuatnya lebih mudah untuk dipahami ketika suatu objek tidak berubah. Namun, di Jawa sangat verbose, khususnya (menurut saya) ketika digunakan pada parameter. Ini bukan untuk mengatakan bahwa orang tidak boleh menggunakannya karena itu verbose, tetapi mereka tidak menggunakannya karena itu verbose.

Beberapa bahasa lain, seperti scala, membuatnya lebih mudah untuk membuat deklarasi akhir ( val ). Dalam bahasa-bahasa ini, deklarasi akhir bisa lebih umum daripada variabel.

Perhatikan bahwa ada banyak kegunaan berbeda dari kata kunci akhir. Sebagian besar posting Anda mencakup item 2 dan 3.

  1. Kelas akhir (JLS 8.1.1.2)
  2. bidang terakhir (JLS 8.3.1.2)
  3. Metode akhir (JLS 8.4.3.3)
  4. Variabel akhir (JLS 4.12.4)
schmmd
sumber
2

Yah untuk memulainya, Konvensi Kode Java resmi tidak mendukung atau melarang penggunaan khususfinal . Artinya, pengembang JDK bebas memilih apa yang mereka inginkan.

Saya tidak bisa membaca pikiran mereka tetapi bagi saya, preferensi untuk menggunakan finalatau tidak telah menjadi masalah fokus. Masalah apakah saya punya cukup waktu untuk berkonsentrasi penuh pada kode atau tidak .

  • Katakanlah, di salah satu proyek saya, kami mampu menghabiskan rata-rata sehari seperti 100 baris kode. Dalam proyek ini, saya memiliki persepsi berbeda finalsebagai sampah yang hanya mengaburkan hal-hal yang sudah cukup jelas diungkapkan dalam kode. Sepertinya pengembang JDK termasuk dalam kategori itu juga.
     
    Di sisi lain, itu benar-benar berlawanan dalam proyek lain, di mana kami menghabiskan rata-rata satu jam pada 100 baris kode. Di sana, saya menemukan diri saya menembak finalseperti senapan mashine dalam kode saya sendiri dan orang lain - hanya karena itu adalah cara tercepat untuk mendeteksi maksud orang yang menulisnya sebelum saya dan, juga, cara tercepat untuk mengomunikasikan niat saya sendiri untuk orang yang akan mengerjakan kode saya nanti.

Ini juga dapat memberikan sedikit dorongan bagi JIT, dan meskipun itu sangat terbatas, JIT tidak bisa membahayakan

Penalaran seperti di atas memang licin. Optimalisasi prematur dapat membahayakan; Donald Knuth lebih jauh menyebutnya "akar segala kejahatan" . Jangan biarkan itu menjebak Anda. Tulis kode bodoh .

agas
sumber
2

Baru-baru ini saya menemukan kegembiraan fitur "Save Actions" di Eclipse IDE. Saya dapat memaksanya untuk memformat ulang kode saya, memasukkan @Overrideanotasi yang hilang , dan melakukan beberapa hal bagus seperti menghapus tanda kurung yang tidak perlu dalam ekspresi atau meletakkanfinal kata kunci di mana-mana secara otomatis setiap kali saya menekan ctrl + S. Saya mengaktifkan beberapa pemicu itu dan, nak, ini sangat membantu!

Ternyata banyak dari pemicu tersebut bertindak seperti cek kewarasan cepat untuk kode saya.

  • Saya bermaksud mengganti metode tetapi anotasi tidak muncul ketika saya menekan ctrl + s ? - mungkin saya mengacaukan tipe parameter di suatu tempat!
  • Beberapa tanda kurung telah dihapus dari kode di save? - mungkin ekspresi logika itu terlalu sulit bagi programmer untuk bergaul dengan cepat. Kalau tidak, mengapa saya menambahkan tanda kurung itu di tempat pertama?
  • Parameter atau variabel lokal itu tidak final. Apakah harus mengubah nilainya?

Ternyata semakin sedikit variabel berubah semakin sedikit masalah yang saya miliki pada waktu debug. Berapa kali Anda mengikuti nilai beberapa variabel hanya untuk menemukan bahwa itu entah bagaimana berubah dari katakan 5 ke 7? "Bagaimana bisa ?!" Anda bertanya pada diri sendiri dan menghabiskan beberapa jam berikutnya melangkah masuk dan keluar dari metode yang tak terhitung jumlahnya untuk mengetahui bahwa Anda telah membuat kesalahan dalam logika Anda. Dan untuk memperbaikinya Anda harus menambahkan satu lagi bendera, beberapa kondisi dan hati-hati mengubah beberapa nilai di sana-sini.

Oh, aku benci debugging! Setiap kali saya menjalankan debugger, saya merasa waktu saya hampir habis dan saya sangat membutuhkan waktu itu untuk membuat setidaknya beberapa impian masa kecil saya menjadi kenyataan! Persetan dengan debugging! finalBerarti tidak ada lagi perubahan nilai yang misterius. Lebih banyak finals => lebih sedikit bagian yang rapuh dalam kode saya => lebih sedikit bug => lebih banyak waktu untuk melakukan hal-hal yang baik!

Sedangkan untuk finalkelas dan metode saya tidak terlalu peduli. Saya suka polimorfisme. Polimorfisme berarti penggunaan kembali berarti lebih sedikit kode berarti lebih sedikit bug. JVM melakukan pekerjaan yang cukup bagus dengan devirtualization dan metode inlining, jadi saya tidak melihat nilai dalam membunuh kemungkinan untuk menggunakan kembali kode untuk manfaat kinerja yang tidak sehat.


Melihat semua finalitu dalam kode agak mengganggu pada awalnya dan membutuhkan waktu untuk terbiasa juga. Beberapa rekan tim saya masih sangat terkejut melihat begitu banyak finalkata kunci. Saya berharap ada pengaturan di IDE untuk pewarnaan sintaks khusus untuk itu. Saya akan senang untuk mengubahnya ke beberapa warna abu-abu (seperti anotasi) sehingga mereka tidak akan terlalu mengganggu ketika membaca kode. Eclipse saat ini memiliki warna terpisah untuk returndan semua kata kunci lainnya tetapi tidak untuk final.

Andrew Андрей Листочкин
sumber
1
Anda mungkin dapat mempertimbangkan melihat ke bahasa fungsional seperti OCaml atau F #. Bahasa-bahasa ini cenderung memerlukan lebih sedikit debugging, salah satu alasannya adalah bahwa semuanya hanya-baca secara default. Sederhananya, begitu ditugaskan, variabel dalam bahasa fungsional tidak berubah.
Abel
1
Ya, saya tahu itu dan saya benar-benar menulis beberapa kode ML dari waktu ke waktu - di situlah saya mendapatkan inspirasi dari :) Ini bukan tentang bahasa yang Anda gunakan tetapi tentang prinsip dan teknik yang Anda terapkan. Orang dapat melakukan semua keharusan dengan Haskell dan donotasi :) Tentu saja, Java bukan bahasa terbaik untuk menulis dalam gaya fungsional tetapi setidaknya itu memungkinkan Anda untuk menulis kode yang kuat -dan itulah yang saya benar-benar pedulikan.
Andrew Андрей Листочкин