ที่มา: abhinavpandey.dev ในบทช่วยสอนนี้ เราจะครอบคลุมพื้นฐานของการใช้ Records ใน Java บันทึกถูกนำมาใช้ใน Java 14 เพื่อเป็นวิธีการลบโค้ดสำเร็จรูปที่เกี่ยวข้องกับการสร้างอ็อบเจ็กต์ Value ในขณะที่ใช้ประโยชน์จากอ็อบเจ็กต์ที่ไม่เปลี่ยนรูป

1. แนวคิดพื้นฐาน
ก่อนที่เราจะพูดถึงรายการต่างๆ เรามาดูปัญหาที่พวกเขาแก้ไขกันก่อน ในการดำเนินการนี้ เราจะต้องจำไว้ว่าค่าอ็อบเจ็กต์ถูกสร้างขึ้นก่อน Java 14 อย่างไร1.1. วัตถุมีค่า
อ็อบเจ็กต์ค่าเป็นส่วนสำคัญของแอปพลิเคชัน Java จัดเก็บข้อมูลที่ต้องถ่ายโอนระหว่างชั้นแอปพลิเคชัน อ็อบเจ็กต์ค่าประกอบด้วยฟิลด์ ตัวสร้าง และวิธีการในการเข้าถึงฟิลด์เหล่านั้น ด้านล่างนี้เป็นตัวอย่างของวัตถุค่า: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. ความเท่าเทียมกันระหว่างออบเจ็กต์ค่า
วัตถุค่ายังสามารถให้วิธีการเปรียบเทียบเพื่อความเท่าเทียมกันได้ ตามค่าเริ่มต้น Java จะเปรียบเทียบความเท่าเทียมกันของวัตถุโดยการเปรียบเทียบที่อยู่หน่วยความจำ อย่างไรก็ตาม ในบางกรณี ออบเจ็กต์ที่มีข้อมูลเดียวกันอาจถือว่าเท่ากัน เพื่อดำเนินการนี้ เราสามารถแทนที่ วิธีการ เท่ากับและ.hashCodeได้ มานำไปใช้กับ คลาส 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. ความไม่เปลี่ยนแปลงของวัตถุค่า
ออบเจ็กต์ค่าจะต้องไม่เปลี่ยนรูป ซึ่งหมายความว่าเราต้องจำกัดวิธีที่เราสามารถเปลี่ยนฟิลด์ของออบเจ็กต์ได้ ขอแนะนำด้วยเหตุผลดังต่อไปนี้:- เพื่อหลีกเลี่ยงความเสี่ยงในการเปลี่ยนแปลงค่าฟิลด์โดยไม่ตั้งใจ
- เพื่อให้แน่ใจว่าวัตถุที่เท่าเทียมกันจะยังคงเหมือนเดิมตลอดชีวิต
- ทำให้สนามเป็นส่วนตัวและเป็นที่สิ้นสุด
- ระบุเฉพาะgetterสำหรับแต่ละฟิลด์ (ไม่มีsetters )
1.4. การลงทะเบียนออบเจ็กต์ค่า
บ่อยครั้งที่เราจำเป็นต้องลงทะเบียนค่าที่มีอยู่ในวัตถุ ซึ่งทำได้โดยการจัดเตรียมเมธอดtoString เมื่อใดก็ตามที่วัตถุถูกลงทะเบียนหรือพิมพ์ เมธอด toString จะถูกเรียก ว่า วิธีที่ง่ายที่สุดคือการพิมพ์ค่าของแต่ละฟิลด์ นี่คือตัวอย่าง:public class Contact {
// ...
@Override
public String toString() {
return "Contact[" +
"name='" + name + '\'' +
", email=" + email +
']';
}
}
2. ลดเทมเพลตด้วย Records
เนื่องจากออบเจ็กต์ที่มีคุณค่าส่วนใหญ่มีความต้องการและฟังก์ชันการทำงานที่เหมือนกัน จึงเป็นการดีที่จะลดความซับซ้อนของกระบวนการสร้างวัตถุเหล่านั้น มาดูกันว่าการบันทึกช่วยให้บรรลุเป้าหมายนี้ได้อย่างไร2.1. การแปลงคลาส Person เป็น Record
มาสร้าง รายการคลาส Contactที่มีฟังก์ชันการทำงานเหมือนกับ คลาส Contactที่กำหนดไว้ข้างต้นpublic record Contact(String name, String email) {}
คีย์เวิร์ดrecordใช้เพื่อสร้างคลาสRecord ผู้โทรสามารถประมวลผลบันทึกได้ในลักษณะเดียวกับชั้นเรียน ตัวอย่างเช่น หากต้องการสร้างอิน ส แตนซ์รายการใหม่ เราสามารถใช้ คีย์เวิร์ดnew
Contact contact = new Contact("John Doe", "johnrocks@gmail.com");
2.2. พฤติกรรมเริ่มต้น
เราได้ลดโค้ดเหลือหนึ่งบรรทัด มาดูกันว่ามีอะไรบ้าง:-
ช่องชื่อและอีเมลเป็นแบบส่วนตัวและเป็นช่องสุดท้ายตามค่าเริ่มต้น
-
รหัสกำหนด "ตัวสร้างแบบบัญญัติ" ที่ใช้ฟิลด์เป็นพารามิเตอร์
-
เข้าถึงช่องต่างๆ ได้ผ่านวิธีการเหมือนทะเยอทะยาน - name()และemail( ) ไม่มีตัวตั้งค่าสำหรับฟิลด์ ดังนั้นข้อมูลในออบเจ็กต์จึงไม่เปลี่ยนรูป
-
ใช้ เมธอด toString เพื่อ พิมพ์ฟิลด์เหมือนกับที่เราทำกับ คลาส Contact
-
ใช้ วิธีเท่ากับและ. hashCode ซึ่งจะรวมทุกช่อง เช่นเดียวกับคลาสContact
2.3 ตัวสร้างมาตรฐาน
ตัวสร้างเริ่มต้นจะใช้ฟิลด์ทั้งหมดเป็นพารามิเตอร์อินพุตและตั้งค่าเป็นฟิลด์ ตัวอย่างเช่น Canonical Constructor เริ่มต้นจะแสดงอยู่ด้านล่าง:public Contact(String name, String email) {
this.name = name;
this.email = email;
}
หากเรากำหนดคอนสตรัคเตอร์ที่มีลายเซ็นเดียวกันในคลาสการบันทึก มันจะถูกใช้แทนคอนสตรัคเตอร์ตามรูปแบบบัญญัติ
3. การทำงานกับบันทึก
เราสามารถเปลี่ยนพฤติกรรมของรายการได้หลายวิธี มาดูกรณีการใช้งานบางส่วนและวิธีทำให้สำเร็จกัน3.1. การแทนที่การใช้งานเริ่มต้น
การใช้งานเริ่มต้นใดๆ สามารถเปลี่ยนแปลงได้โดยการแทนที่ ตัวอย่างเช่น หากเราต้องการเปลี่ยนพฤติกรรมของ เมธอด toStringเราก็สามารถแทนที่มันระหว่างเครื่องหมายปีกกา{}ได้public record Contact(String name, String email) {
@Override
public String toString() {
return "Contact[" +
"name is '" + name + '\'' +
", email is" + email +
']';
}
}
ในทำนองเดียวกัน เราสามารถแทนที่ วิธีการ เท่ากับและhashCodeได้
3.2. ชุดเครื่องมือก่อสร้างขนาดกะทัดรัด
บางครั้งเราต้องการให้คอนสตรัคเตอร์ทำมากกว่าแค่เริ่มต้นฟิลด์ เมื่อต้องการทำเช่นนี้ เราสามารถเพิ่มการดำเนินการที่จำเป็นลงในรายการของเราใน Compact Constructor เรียกว่ากะทัดรัดเนื่องจากไม่จำเป็นต้องกำหนดค่าเริ่มต้นฟิลด์หรือรายการพารามิเตอร์public record Contact(String name, String email) {
public Contact {
if(!email.contains("@")) {
throw new IllegalArgumentException("Invalid email");
}
}
}
โปรดทราบว่าไม่มีรายการพารามิเตอร์ และการกำหนดค่าเริ่มต้นของชื่อและอีเมลจะเกิดขึ้นในเบื้องหลังก่อนดำเนินการตรวจสอบ
3.3. การเพิ่มตัวสร้าง
คุณสามารถเพิ่มตัวสร้างหลายตัวลงในเรกคอร์ดได้ ลองดูตัวอย่างและข้อจำกัดบางประการ ขั้นแรก ให้เพิ่มตัวสร้างที่ถูกต้องใหม่: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;
}
}
ในกรณี แรก เข้าถึงตัวสร้างเริ่มต้นโดยใช้ คีย์เวิร์ด นี้ ตัวสร้างตัวที่สองจะแทนที่ตัวสร้างเริ่มต้นเนื่องจากมีรายการพารามิเตอร์เดียวกัน ในกรณีนี้ รายการเองจะไม่สร้างตัวสร้างเริ่มต้น มีข้อ จำกัด หลายประการเกี่ยวกับตัวสร้าง
1. ตัวสร้างเริ่มต้นควรถูกเรียกจากตัวสร้างอื่น ๆ เสมอ
ตัวอย่างเช่น โค้ดด้านล่างนี้จะไม่คอมไพล์:public record Contact(String name, String email) {
public Contact(String name) {
this.name = "John Doe";
this.email = null;
}
}
กฎนี้ช่วยให้แน่ใจว่าฟิลด์จะเตรียมใช้งานอยู่เสมอ นอกจากนี้ยังรับประกันได้ว่าการดำเนินการที่กำหนดไว้ในตัวสร้างขนาดกะทัดรัดจะได้รับการดำเนินการเสมอ
2. ไม่สามารถแทนที่ตัวสร้างเริ่มต้นได้หากมีการกำหนดตัวสร้างแบบกะทัดรัด
เมื่อมีการกำหนดตัวสร้างแบบกะทัดรัด ตัวสร้างเริ่มต้นจะถูกสร้างขึ้นโดยอัตโนมัติด้วยการกำหนดค่าเริ่มต้นและตรรกะของตัวสร้างแบบกะทัดรัด ในกรณีนี้ คอมไพเลอร์จะไม่อนุญาตให้เรากำหนดคอนสตรัคเตอร์ที่มีอาร์กิวเมนต์เดียวกันกับคอนสตรัคเตอร์เริ่มต้น ตัวอย่างเช่น ในโค้ดนี้ การคอมไพล์จะไม่เกิดขึ้น: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. การใช้อินเทอร์เฟซ
เช่นเดียวกับคลาสอื่นๆ เราสามารถใช้อินเทอร์เฟซในบันทึกได้public record Contact(String name, String email) implements Comparable<Contact> {
@Override
public int compareTo(Contact o) {
return name.compareTo(o.name);
}
}
โน๊ตสำคัญ. เพื่อให้มั่นใจว่าจะไม่เปลี่ยนรูปแบบโดยสมบูรณ์ จึงไม่สามารถสืบทอดบันทึกได้ ผลงานถือเป็นที่สิ้นสุดและไม่สามารถขยายได้ พวกเขายังไม่สามารถขยายคลาสอื่นได้
3.5. การเพิ่มวิธีการ
นอกจากตัวสร้างซึ่งจะแทนที่วิธีการและการใช้งานอินเทอร์เฟซแล้ว เรายังสามารถเพิ่มวิธีการใดๆ ที่เราต้องการได้อีกด้วย ตัวอย่างเช่น:public record Contact(String name, String email) {
String printName() {
return "My name is:" + this.name;
}
}
เรายังสามารถเพิ่มวิธีการแบบคงที่ได้ ตัวอย่างเช่น หากเราต้องการมีวิธีการคงที่ที่ส่งคืนนิพจน์ทั่วไปซึ่งเราสามารถตรวจสอบอีเมลได้ เราก็สามารถกำหนดได้ดังที่แสดงด้านล่าง:
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. การเพิ่มฟิลด์
เราไม่สามารถเพิ่มฟิลด์อินสแตนซ์ลงในบันทึกได้ อย่างไรก็ตาม เราสามารถเพิ่มฟิลด์แบบคงที่ได้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;
}
}
โปรดทราบว่าไม่มีข้อจำกัดโดยนัยในฟิลด์คงที่ หากจำเป็น อาจเปิดเผยต่อสาธารณะและไม่ใช่ที่สิ้นสุด
GO TO FULL VERSION