Saya baru-baru ini menemukan konstruk Java yang belum pernah saya lihat sebelumnya dan bertanya-tanya apakah saya harus menggunakannya. Tampaknya disebut blok penginisialisasi .
public class Test {
public Test() { /* first constructor */ }
public Test(String s) { /* second constructor */ }
// Non-static initializer block - copied into every constructor:
{
doStuff();
}
}
Blok kode akan disalin ke setiap konstruktor, yaitu jika Anda memiliki beberapa konstruktor, Anda tidak perlu menulis ulang kode.
Namun, saya melihat tiga kelemahan utama menggunakan sintaks ini:
- Ini adalah salah satu dari sedikit kasus di Jawa di mana urutan kode Anda penting, karena Anda dapat menentukan beberapa blok kode dan akan dieksekusi dalam urutan yang ditulis. Ini tampaknya berbahaya bagi saya karena hanya mengubah urutan blok kode akan benar-benar mengubah kode.
- Saya tidak benar-benar melihat manfaatnya dengan menggunakannya. Dalam kebanyakan kasus, konstruktor akan memanggil satu sama lain dengan beberapa nilai yang telah ditentukan. Bahkan jika ini tidak terjadi, kode hanya dapat dimasukkan ke dalam metode pribadi dan dipanggil dari setiap konstruktor.
- Ini mengurangi keterbacaan, karena Anda bisa meletakkan blok di akhir kelas dan konstruktor biasanya di awal kelas. Sangat kontra-intuitif untuk melihat bagian yang sama sekali berbeda dari file kode jika Anda tidak mengharapkan hal itu diperlukan.
Jika pernyataan saya di atas benar, mengapa (dan kapan) konstruksi bahasa ini diperkenalkan? Apakah ada kasus penggunaan yang sah?
{ doStuff(); }
pada tingkat kelas adalah blok penginisialisasi.doStuff()
Jawaban:
Ada dua kasus di mana saya menggunakan blok penginisialisasi.
Yang pertama adalah untuk menginisialisasi anggota akhir. Di Jawa, Anda dapat menginisialisasi anggota akhir baik sesuai dengan deklarasi, atau Anda dapat menginisialisasi dalam konstruktor. Dalam suatu metode, dilarang untuk menugaskan anggota akhir.
Ini valid:
Ini juga berlaku:
Ini tidak valid:
Jika Anda memiliki banyak konstruktor, dan jika Anda tidak dapat menginisialisasi anggota akhir sebaris (karena logika inisialisasi terlalu kompleks), atau jika konstruktor tidak dapat menyebut diri mereka, maka Anda dapat menyalin / menempelkan kode inisialisasi, atau Anda dapat menggunakan blok penginisialisasi.
Kasus penggunaan lain yang saya miliki untuk blok penginisialisasi adalah untuk membangun struktur data pembantu kecil. Saya mendeklarasikan anggota, dan meletakkan nilai di dalamnya tepat setelah deklarasi di blok penginisialisasi sendiri.
sumber
squareVal = val * val
akan mengeluh tentang mengakses nilai yang tidak diinisialisasi. Blok inisialisasi tidak mungkin bergantung pada argumen yang diteruskan ke konstruktor. Solusi yang biasa saya lihat untuk masalah semacam itu adalah mendefinisikan konstruktor "basis" tunggal dengan logika kompleks, dan untuk mendefinisikan semua konstruktor lain dalam hal itu. Sebagian besar penggunaan inisialisasi instance, pada kenyataannya, dapat diganti dengan pola itu.Secara umum, jangan gunakan blok penginisialisasi non-statis (dan mungkin hindari yang statis juga).
Sintaks yang membingungkan
Melihat pertanyaan ini, ada 3 jawaban, namun Anda membodohi 4 orang dengan sintaks ini. Saya adalah salah satu dari mereka dan saya telah menulis Java selama 16 tahun! Jelas, sintaksnya berpotensi rawan kesalahan! Aku akan menjauh darinya.
Konstruktor Telescoping
Untuk hal-hal yang sangat sederhana, Anda dapat menggunakan konstruktor "telescoping" untuk menghindari kebingungan ini:
Pola Pembangun
Jika Anda perlu melakukanStuff () di akhir setiap konstruktor atau inisialisasi canggih lainnya, mungkin pola pembangun akan menjadi yang terbaik. Josh Bloch mendaftar beberapa alasan mengapa pembangun adalah ide yang bagus. Pembangun membutuhkan sedikit waktu untuk menulis, tetapi ditulis dengan benar, mereka senang digunakan.
Initializer Loop Statis
Saya sering menggunakan penginisialisasi statis banyak, tetapi kadang-kadang berlari ke loop di mana 2 kelas tergantung pada blok penginisialisasi statis masing-masing dipanggil sebelum kelas bisa dimuat penuh. Ini menghasilkan "gagal memuat kelas" atau pesan kesalahan yang juga tidak jelas. Saya harus membandingkan file dengan versi kerja terakhir yang diketahui dalam kontrol sumber untuk mencari tahu apa masalahnya. Tidak menyenangkan sama sekali.
Inisialisasi Malas
Mungkin inisialisasi statis baik untuk alasan kinerja ketika mereka bekerja dan tidak terlalu membingungkan. Tetapi secara umum, saya lebih suka inisialisasi malas daripada inisialisasi statis hari ini. Sudah jelas apa yang mereka lakukan, saya belum menemukan bug pemuatan kelas dengan mereka, dan mereka bekerja dalam lebih banyak situasi inisialisasi daripada blok inisialisasi.
Definisi Data
Alih-alih inisialisasi statis untuk membangun struktur data, (bandingkan dengan contoh dalam jawaban lain), saya sekarang menggunakan fungsi pembantu definisi data Paguro yang tidak berubah :
Conculsion
Pada awal Java, blok initializer adalah satu-satunya cara untuk melakukan beberapa hal, tetapi sekarang mereka membingungkan, rentan kesalahan, dan dalam banyak kasus telah digantikan oleh alternatif yang lebih baik (dirinci di atas). Sangat menarik untuk mengetahui tentang blok penginisialisasi jika Anda melihatnya dalam kode warisan, atau mereka muncul pada suatu pengujian, tetapi jika saya sedang melakukan tinjauan kode dan saya melihatnya dalam kode baru, saya akan meminta Anda untuk membenarkan mengapa tidak ada alternatif di atas cocok sebelum memberikan kode Anda jempol.
sumber
Selain inisialisasi variabel instan yang dinyatakan sebagai
final
(lihat jawaban barjak ), saya juga akan menyebutkanstatic
blok inisialisasi.Anda dapat menggunakannya sebagai "kontruktor statis".
Dengan begitu Anda dapat melakukan inisialisasi kompleks pada variabel statis saat pertama kali kelas direferensikan.
Ini adalah contoh yang terinspirasi dari contoh barjak:
sumber
Seperti halnya blok penginisialisasi non-statis, fungsi kosongnya adalah untuk bertindak sebagai konstruktor default di kelas anonim. Itu pada dasarnya satu-satunya hak mereka untuk hidup.
sumber
Saya sepenuhnya setuju dengan pernyataan 1, 2, 3. Saya juga tidak pernah menggunakan inisialisasi blok karena alasan ini dan saya tidak tahu mengapa itu ada di Jawa.
Namun, saya dipaksa untuk menggunakan initializer blok statis dalam satu kasus: ketika saya harus instantiate bidang statis yang konstruktornya dapat melempar pengecualian diperiksa.
Tetapi yang harus Anda lakukan:
Saya menemukan idiom ini sangat jelek (itu juga mencegah Anda untuk menandai
context
sebagaifinal
) tetapi ini adalah satu-satunya cara yang didukung oleh Java untuk menginisialisasi bidang tersebut.sumber
context = null;
di blok tangkap Anda, bahwa Anda mungkin dapat menyatakan konteks sebagai final.The final field context may already have been assigned
static { JAXBContext tempCtx = null; try { tempCtx = JAXBContext.newInstance(Foo.class); } catch (JAXBException ignored) { ; } context = tempCtx; }