JavaRush /จาวาบล็อก /Random-TH /คอฟฟี่เบรค #128. คู่มือประวัติ Java

คอฟฟี่เบรค #128. คู่มือประวัติ Java

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

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. ความไม่เปลี่ยนแปลงของวัตถุค่า

ออบเจ็กต์ค่าจะต้องไม่เปลี่ยนรูป ซึ่งหมายความว่าเราต้องจำกัดวิธีที่เราสามารถเปลี่ยนฟิลด์ของออบเจ็กต์ได้ ขอแนะนำด้วยเหตุผลดังต่อไปนี้:
  • เพื่อหลีกเลี่ยงความเสี่ยงในการเปลี่ยนแปลงค่าฟิลด์โดยไม่ตั้งใจ
  • เพื่อให้แน่ใจว่าวัตถุที่เท่าเทียมกันจะยังคงเหมือนเดิมตลอดชีวิต
เนื่องจาก คลาส Contactนั้นไม่เปลี่ยนรูปอยู่แล้ว ตอนนี้เรา:
  1. ทำให้สนามเป็นส่วนตัวและเป็นที่สิ้นสุด
  2. ระบุเฉพาะ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. พฤติกรรมเริ่มต้น

เราได้ลดโค้ดเหลือหนึ่งบรรทัด มาดูกันว่ามีอะไรบ้าง:
  1. ช่องชื่อและอีเมลเป็นแบบส่วนตัวและเป็นช่องสุดท้ายตามค่าเริ่มต้น

  2. รหัสกำหนด "ตัวสร้างแบบบัญญัติ" ที่ใช้ฟิลด์เป็นพารามิเตอร์

  3. เข้าถึงช่องต่างๆ ได้ผ่านวิธีการเหมือนทะเยอทะยาน - name()และemail( ) ไม่มีตัวตั้งค่าสำหรับฟิลด์ ดังนั้นข้อมูลในออบเจ็กต์จึงไม่เปลี่ยนรูป

  4. ใช้ เมธอด toString เพื่อ พิมพ์ฟิลด์เหมือนกับที่เราทำกับ คลาส Contact

  5. ใช้ วิธีเท่ากับและ. 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;
    }
}
โปรดทราบว่าไม่มีข้อจำกัดโดยนัยในฟิลด์คงที่ หากจำเป็น อาจเปิดเผยต่อสาธารณะและไม่ใช่ที่สิ้นสุด

บทสรุป

บันทึกเป็นวิธีที่ดีในการกำหนดคลาสข้อมูล สะดวกและมีประสิทธิภาพมากกว่าแนวทาง JavaBeans/POJO มาก เนื่องจากง่ายต่อการนำไปใช้ จึงควรเลือกใช้มากกว่าวิธีอื่นในการสร้างออบเจ็กต์คุณค่า
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION