Segera, di Java 14 mendatang, fitur sintaksis baru akan muncul - catatan. Setelah mempelajari pratinjau , yang menjelaskan secara singkat bagaimana rekaman terlihat dan dengan "apa yang mereka makan", saya berani mengadaptasi dokumen ke bahasa Rusia untuk Habr. Siapa yang peduli - selamat datang di kucing.
Ringkasan
Entri memungkinkan Anda untuk memperluas kemampuan Java. Mereka menyediakan sintaksis ringkas untuk mendeklarasikan kelas yang merupakan pembawa sederhana dari kumpulan data yang konstan dan tidak berubah.
Alasan dan Tujuan
Keluhan bahwa “Java terlalu bertele-tele” dan bahwa Anda perlu “upacara” dengannya cukup umum. Alasannya adalah kelas yang dirancang hanya untuk menyimpan kumpulan data tertentu. Untuk menulis kelas seperti itu dengan benar, Anda perlu menulis banyak kode formal, berulang dan rawan kesalahan: konstruktor, getter dan setter, equals (), hashCode (), toString (), dll. Pengembang terkadang curang dan tidak mengesampingkan equals () dan hashCode (), yang pada gilirannya dapat menyebabkan perilaku atau masalah yang tidak biasa dengan debugging. Atau, ketika pengembang tidak ingin mendeklarasikan kelas lain, mereka meresepkan alternatif, tetapi tidak cukup cocok, hanya karena memiliki "bentuk yang benar".
Lingkungan pengembangan akan membantu mendaftarkan sebagian besar kode di kelas, tetapi tidak akan membantu pengembang membaca kode ini untuk dengan cepat menavigasi di antara puluhan baris kode boilerplate dan memahami bahwa kelas ini adalah pembawa data biasa. Pemodelan kode Java set data standar harus sederhana untuk ditulis, dipahami, dan divalidasi.
Sekilas, sepertinya catatan dimaksudkan untuk mengurangi kode templat. Kami menempatkan sasaran semantik di dalamnya:
“memodelkan data sebagai data” (memodelkan data sebagai data). Jika semantiknya benar, maka kode templat akan melakukan semuanya sendiri tanpa partisipasi pengembang. Bagaimanapun, mendeklarasikan kumpulan data persisten harus mudah, jelas, dan singkat.
Gol yang tidak
Kami tidak menetapkan tujuan “mendeklarasikan perang” pada kode boilerplate. Secara khusus, kami tidak bermaksud untuk memecahkan masalah kelas yang bisa berubah menggunakan konvensi penamaan komponen JavaBean. Meskipun properti, metaprogramming, dan pembuatan kode berbasis anotasi sering disarankan sebagai "solusi" untuk masalah ini, menambahkan fitur-fitur ini juga bukan tujuan kami.
Deskripsi
Entri adalah jenis deklarasi tipe baru di Jawa. Seperti halnya enum, menulis adalah kelas yang secara fungsional terbatas. Ini mengumumkan pandangannya dan menyediakan API yang dibangun berdasarkan pandangan itu. Entri tidak memisahkan API dari presentasi dan, pada gilirannya, ringkas.
Entri berisi nama dan deskripsi status. Deskripsi keadaan menyatakan komponen dari catatan ini. Secara opsional, catatan mungkin memiliki badan. Sebagai contoh:
record Point(int x, int y) { }
Karena semantik catatan adalah pembawa data sederhana, mereka secara otomatis menerima elemen standar:
- Bidang final pribadi untuk setiap komponen negara;
- Metode membaca publik untuk setiap komponen negara dengan nama dan jenis yang sama dengan komponen;
- Konstruktor publik yang cocok dengan tanda tangan catatan; itu menginisialisasi setiap bidang dari argumen yang sesuai;
- Implementasi equals () dan hashCode (), yang mengatakan bahwa dua record adalah sama jika mereka memiliki tipe yang sama dan mengandung status yang sama;
- Implementasi toString (), yang mencakup representasi string dari semua komponen rekaman dengan nama mereka.
Dengan kata lain, penyajian catatan sepenuhnya didasarkan pada deskripsi negara. Juga, berdasarkan status catatan, pembentukan equals (), hashCode () dan toString () terjadi.
Keterbatasan
Catatan tidak bisa mewarisi kelas lain dan tidak bisa mendeklarasikan bidang objek, kecuali untuk bidang akhir pribadi yang sesuai dengan komponen negara. Setiap bidang yang dideklarasikan lainnya harus statis. Batasan-batasan ini memastikan bahwa deskripsi negara dengan sendirinya mendefinisikan pandangan.
Entri bersifat final dan tidak bisa abstrak. Batasan ini menunjukkan bahwa API catatan hanya ditentukan oleh deskripsi keadaan dan tidak dapat diperpanjang kemudian dengan kelas atau catatan lain.
Komponen perekaman bersifat final. Pembatasan ini menerapkan prinsip "tidak berubah secara default", yang banyak digunakan untuk kumpulan data.
Selain keterbatasan yang disebutkan di atas, catatan berperilaku seperti kelas biasa: mereka dapat dinyatakan sebagai tingkat atas atau bersarang, mereka bisa menjadi generik, mereka dapat mengimplementasikan antarmuka. Rekaman dibuat dengan memanggil operator baru. Badan penulisan dapat mendeklarasikan metode statis, bidang statis, blok inisialisasi statis, konstruktor, metode contoh, contoh blok inisialisasi, dan tipe bersarang. Catatan dan komponen keadaan individu dapat dijelaskan. Jika catatan bersarang, maka itu statis; ini menghilangkan situasi dengan instance bersarang yang secara otomatis dapat menambahkan status ke catatan.
Entri yang Dinyatakan Secara Eksplisit
Meskipun penerapan standar getter, serta metode equals (), hashCode (), dan toString (), dapat diterima untuk sebagian besar kasus penggunaan, pengembang memiliki opsi untuk mengganti penerapan standar. Namun, Anda harus sangat berhati-hati saat mengganti metode equals / hashCode.
Perhatian khusus diberikan pada deklarasi eksplisit dari konstruktor kanonik, yang tanda tangannya cocok dengan deskripsi keadaan catatan. Konstruktor dapat dideklarasikan tanpa daftar formal parameter: dalam hal ini, diasumsikan bahwa itu bertepatan dengan deskripsi keadaan, dan setiap bidang rekaman secara implisit diinisialisasi dengan standar menutup badan konstruktor dari parameter formal yang sesuai (ini. X = x) pada output. Ini memungkinkan konstruktor kanonik hanya memeriksa dan menyesuaikan parameternya, serta melewatkan inisialisasi bidang eksplisit. Sebagai contoh:
record Range(int lo, int hi) { public Range { if (lo > hi) throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi)); } }
Tata bahasa
RecordDeclaration: {ClassModifier} record TypeIdentifier [TypeParameters] (RecordComponents) [SuperInterfaces] [RecordBody] RecordComponents: {RecordComponent {, RecordComponent}} RecordComponent: {Annotation} UnannType Identifier RecordBody: { {RecordBodyDeclaration} } RecordBodyDeclaration: ClassBodyDeclaration RecordConstructorDeclaration RecordConstructorDeclaration: {Annotation} {ConstructorModifier} [TypeParameters] SimpleTypeName [Throws] ConstructorBody
Anotasi untuk Komponen Perekaman
Anotasi, anotasi dapat diterapkan untuk merekam komponen jika berlaku untuk komponen, parameter, bidang, atau metode. Anotasi iklan yang berlaku untuk semua komponen ini berlaku untuk deklarasi implisit elemen apa pun yang diperlukan.
Ketik anotasi yang mengubah tipe komponen rekaman meluas ke tipe dalam deklarasi implisit elemen yang diperlukan (misalnya, parameter konstruktor, deklarasi lapangan, dan metode). Deklarasi eksplisit dari elemen yang diperlukan harus sama persis dengan tipe komponen catatan yang sesuai, tidak termasuk penjelasan jenis.
API Refleksi
Metode publik berikut akan ditambahkan ke
java.lang.Class :
- RecordComponent [] getRecordComponents ()
- boolean isRecord ()
Metode
getRecordComponents () mengembalikan array
java.lang.reflect.RecordComponent , di mana
java.lang.reflect.RecordComponent adalah kelas baru.
Elemen-elemen dari array ini sesuai dengan komponen catatan dan pergi dalam urutan yang sama di mana mereka dinyatakan dalam catatan. Informasi tambahan dapat diekstraksi dari setiap
RecordComponent dalam array, termasuk nama, tipe, generik, serta nilainya.
Metode
isRecord () mengembalikan
true jika kelas ini dinyatakan sebagai rekaman. (Mirip dengan metode
isEnum () ).
Alternatif
Rekaman dapat didefinisikan sebagai bentuk kondisional dari tupel. Alih-alih catatan, kita dapat menggunakan tupel struktural. Meskipun tuple menawarkan cara yang lebih ringan untuk mengekspresikan beberapa set data, hasilnya seringkali kurang informatif:
- Prinsip utama filosofi Jawa adalah bahwa nama itu penting . Kelas dan elemennya membawa nama yang relevan dengan konten mereka, sedangkan tupel dan komponennya tidak. Yaitu, kelas Person dengan properti firstName dan lastName lebih mudah dipahami dan dapat diandalkan daripada tupel anonim dari String dan String .
- Kelas mendukung validasi keadaan melalui konstruktornya, tuple tidak. Beberapa set data, seperti rentang numerik, memiliki invarian yang nantinya dapat direferensikan jika digunakan oleh konstruktor;
- Kelas mungkin memiliki perilaku berdasarkan negara mereka; kombinasi keadaan dan perilaku menjadikan perilaku itu sendiri lebih eksplisit dan mudah diakses. Tuples, hanya sebagai kumpulan data, tidak menawarkan kesempatan seperti itu.
Ketergantungan
Rekaman cocok dengan
tipe yang terisolasi (JEP 360) ; bersama dengan tipe yang terisolasi, catatan membentuk suatu konstruk, sering disebut
tipe data aljabar. Selain itu, entri itu sendiri memungkinkan
pencocokan pola . Karena catatan mengaitkan API mereka dengan deskripsi keadaan, kita akhirnya bisa juga mendapatkan pola dekonstruksi untuk catatan dan menggunakan informasi kelas terisolasi dalam
pernyataan switch .