Sumber: abhinavpandey.dev Dalam tutorial ini, kita akan membahas dasar-dasar penggunaan Records di Java. Catatan diperkenalkan di Java 14 sebagai cara untuk menghapus kode boilerplate di sekitar pembuatan objek Nilai sambil memanfaatkan objek yang tidak dapat diubah.
1. Konsep dasar
Sebelum kita masuk ke entri itu sendiri, mari kita lihat masalah yang dipecahkannya. Untuk melakukan ini, kita harus mengingat bagaimana objek nilai dibuat sebelum Java 14.1.1. Nilai benda
Objek nilai merupakan bagian integral dari aplikasi Java. Mereka menyimpan data yang perlu ditransfer antar lapisan aplikasi. Objek nilai berisi bidang, konstruktor, dan metode untuk mengakses bidang tersebut. Di bawah ini adalah contoh objek nilai:public class Contact {
private final String name;
private final String email;
public Contact(String name, String email) {
this.name = name;
this.email = email;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
}
1.2. Kesetaraan antar objek Nilai
Objek nilai juga dapat memberikan cara untuk membandingkannya demi kesetaraan. Secara default, Java membandingkan kesetaraan objek dengan membandingkan alamat memorinya. Namun, dalam beberapa kasus, objek yang berisi data yang sama dapat dianggap sama. Untuk mengimplementasikan ini, kita dapat mengganti metode sama dengan dan .hashCode . Mari kita implementasikan untuk kelas Contact :public class Contact {
// ...
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Contact contact = (Contact) o;
return Object.equals(email, contact.email) &&
Objects.equals(name, contact.name);
}
@Override
public int hashCode() {
return Objects.hash(name, email);
}
}
1.3. Kekekalan objek Nilai
Objek nilai harus tidak dapat diubah. Artinya kita harus membatasi cara kita mengubah bidang suatu objek. Hal ini disarankan karena alasan berikut:- Untuk menghindari risiko perubahan nilai bidang secara tidak sengaja.
- Untuk memastikan bahwa objek yang sama tetap sama sepanjang hidup mereka.
- menjadikan bidang itu pribadi dan final .
- hanya menyediakan pengambil untuk setiap bidang (tidak ada penyetel ).
1.4. Mendaftarkan objek Nilai
Seringkali kita perlu mendaftarkan nilai-nilai yang terkandung dalam objek. Hal ini dilakukan dengan menyediakan metode toString . Setiap kali suatu objek didaftarkan atau dicetak, metode toString dipanggil . Cara termudah di sini adalah dengan mencetak nilai setiap bidang. Berikut ini contohnya:public class Contact {
// ...
@Override
public String toString() {
return "Contact[" +
"name='" + name + '\'' +
", email=" + email +
']';
}
}
2. Kurangi template dengan Records
Karena sebagian besar objek nilai memiliki kebutuhan dan fungsi yang sama, alangkah baiknya jika proses pembuatannya disederhanakan. Mari kita lihat bagaimana rekaman membantu mencapai hal ini.2.1. Mengonversi kelas Person menjadi Record
Mari kita buat entri kelas Kontak yang memiliki fungsi yang sama dengan kelas Kontak yang didefinisikan di atas.public record Contact(String name, String email) {}
Kata kunci record digunakan untuk membuat kelas Record . Catatan dapat diproses oleh pemanggil dengan cara yang sama seperti kelas. Misalnya untuk membuat instance entri baru, kita dapat menggunakan kata kunci new .
Contact contact = new Contact("John Doe", "johnrocks@gmail.com");
2.2. Perilaku Default
Kami telah mengurangi kode menjadi satu baris. Mari kita daftar apa saja yang termasuk di dalamnya:-
Bidang nama dan email bersifat pribadi dan final secara default.
-
Kode tersebut mendefinisikan "konstruktor kanonik" yang menggunakan bidang sebagai parameter.
-
Bidang dapat diakses melalui metode seperti pengambil - name() dan email() . Tidak ada penyetel untuk bidang, sehingga data dalam objek menjadi tidak dapat diubah.
-
Menerapkan metode toString untuk mencetak bidang seperti yang kami lakukan untuk kelas Kontak .
-
Menerapkan metode sama dengan dan .hashCode . Mereka menyertakan semua bidang, seperti kelas Contact .
2.3 Konstruktor kanonik
Konstruktor default mengambil semua bidang sebagai parameter masukan dan menetapkannya ke bidang. Misalnya, Konstruktor Canonical default ditunjukkan di bawah ini:public Contact(String name, String email) {
this.name = name;
this.email = email;
}
Jika kita mendefinisikan konstruktor dengan tanda tangan yang sama di kelas rekaman, konstruktor tersebut akan digunakan sebagai pengganti konstruktor kanonik.
3. Bekerja dengan catatan
Kita dapat mengubah perilaku entri dalam beberapa cara. Mari kita lihat beberapa kasus penggunaan dan cara mencapainya.3.1. Mengganti implementasi default
Implementasi default apa pun dapat diubah dengan menimpanya. Misalnya, jika kita ingin mengubah perilaku metode toString , maka kita bisa menggantinya di antara kurung kurawal {} .public record Contact(String name, String email) {
@Override
public String toString() {
return "Contact[" +
"name is '" + name + '\'' +
", email is" + email +
']';
}
}
Demikian pula, kita dapat mengganti metode sama dengan dan kode hash .
3.2. Kit konstruksi kompak
Terkadang kita ingin konstruktor melakukan lebih dari sekadar menginisialisasi kolom. Untuk melakukan ini, kita dapat menambahkan operasi yang diperlukan ke entri kita di Compact Constructor. Disebut ringkas karena tidak perlu menentukan inisialisasi bidang atau daftar parameter.public record Contact(String name, String email) {
public Contact {
if(!email.contains("@")) {
throw new IllegalArgumentException("Invalid email");
}
}
}
Perhatikan bahwa tidak ada daftar parameter, dan inisialisasi nama dan email terjadi di latar belakang sebelum pemeriksaan dilakukan.
3.3. Menambahkan Konstruktor
Anda dapat menambahkan beberapa konstruktor ke sebuah rekaman. Mari kita lihat beberapa contoh dan batasannya. Pertama, mari tambahkan konstruktor baru yang valid:public record Contact(String name, String email) {
public Contact(String email) {
this("John Doe", email);
}
// replaces the default constructor
public Contact(String name, String email) {
this.name = name;
this.email = email;
}
}
Dalam kasus pertama, konstruktor default diakses menggunakan kata kunci this . Konstruktor kedua menggantikan konstruktor default karena memiliki daftar parameter yang sama. Dalam hal ini, entri itu sendiri tidak akan membuat konstruktor default. Ada beberapa batasan pada konstruktor.
1. Konstruktor default harus selalu dipanggil dari konstruktor lainnya.
Misalnya, kode di bawah ini tidak dapat dikompilasi:public record Contact(String name, String email) {
public Contact(String name) {
this.name = "John Doe";
this.email = null;
}
}
Aturan ini memastikan bahwa bidang selalu diinisialisasi. Juga dijamin bahwa operasi yang ditentukan dalam konstruktor kompak selalu dijalankan.
2. Tidak mungkin mengganti konstruktor default jika konstruktor kompak ditentukan.
Ketika konstruktor kompak ditentukan, konstruktor default secara otomatis dibuat dengan inisialisasi dan logika konstruktor kompak. Dalam hal ini, kompiler tidak akan mengizinkan kita mendefinisikan konstruktor dengan argumen yang sama dengan konstruktor default. Misalnya, dalam kode ini kompilasi tidak akan terjadi:public record Contact(String name, String email) {
public Contact {
if(!email.contains("@")) {
throw new IllegalArgumentException("Invalid email");
}
}
public Contact(String name, String email) {
this.name = name;
this.email = email;
}
}
3.4. Menerapkan Antarmuka
Seperti halnya kelas mana pun, kita dapat mengimplementasikan antarmuka dalam rekaman.public record Contact(String name, String email) implements Comparable<Contact> {
@Override
public int compareTo(Contact o) {
return name.compareTo(o.name);
}
}
Catatan penting. Untuk memastikan kekekalan yang lengkap, catatan tidak dapat diwariskan. Entri bersifat final dan tidak dapat diperluas. Mereka juga tidak bisa memperluas kelas lain.
3.5. Menambahkan Metode
Selain konstruktor, yang mengesampingkan metode dan implementasi antarmuka, kita juga dapat menambahkan metode apa pun yang kita inginkan. Misalnya:public record Contact(String name, String email) {
String printName() {
return "My name is:" + this.name;
}
}
Kami juga dapat menambahkan metode statis. Misalnya, jika kita ingin memiliki metode statis yang mengembalikan ekspresi reguler yang dapat digunakan untuk memeriksa email, maka kita dapat mendefinisikannya seperti yang ditunjukkan di bawah ini:
public record Contact(String name, String email) {
static Pattern emailRegex() {
return Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
}
}
3.6. Menambahkan bidang
Kami tidak dapat menambahkan kolom instance ke rekaman. Namun, kita dapat menambahkan kolom statis.public record Contact(String name, String email) {
private static final Pattern EMAIL_REGEX_PATTERN = Pattern
.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE);
static Pattern emailRegex() {
return EMAIL_REGEX_PATTERN;
}
}
Perhatikan bahwa tidak ada batasan implisit dalam bidang statis. Jika perlu, dokumen tersebut mungkin tersedia untuk umum dan belum bersifat final.
GO TO FULL VERSION