0Pricing
Java Academy · บทเรียน

ตัวสร้างแบบกระชับและการตรวจสอบความถูกต้อง

เพิ่มตรรกะตรวจสอบความถูกต้องภายในตัวสร้างแบบกระชับ เพื่อรับรองความสมบูรณ์ของข้อมูล

ตัวสร้างแบบกระชับและการตรวจสอบความถูกต้อง เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คอนสตรักเตอร์แบบย่อ

คอนสตรักเตอร์แบบย่อในเรคคอร์ดจะทำงานก่อนกำหนดค่าคอมโพเนนต์ ช่วยให้คุณตรวจสอบหรือปรับรูปแบบข้อมูลได้โดยไม่ต้องเขียนคำสั่งกำหนดค่าคอมโพเนนต์ซ้ำ

คอนสตรักเตอร์มาตรฐานเทียบกับคอนสตรักเตอร์แบบย่อ

คอนสตรักเตอร์หลักแบบมาตรฐานจะกำหนดค่าคอมโพเนนต์อย่างชัดเจน ส่วนคอนสตรักเตอร์แบบย่อจะไม่ระบุรายการพารามิเตอร์และคำสั่งกำหนดค่า เพราะระบบจะดำเนินการให้อัตโนมัติหลังจากบอดีทำงานเสร็จ

// Standard canonical constructor
record Range(int min, int max) {
    Range(int min, int max) {
        if (min > max) throw new IllegalArgumentException("min > max");
        this.min = min;  // explicit assignment
        this.max = max;
    }
}

// Compact constructor (same behavior, less code)
record Range2(int min, int max) {
    Range2 {  // no parameter list, no assignments
        if (min > max) throw new IllegalArgumentException("min > max");
        // components are assigned automatically after this block
    }
}

การตรวจสอบข้อมูลในคอนสตรักเตอร์แบบย่อ

คอนสตรักเตอร์แบบย่อเป็นวิธีมาตรฐานสำหรับตรวจสอบข้อมูลของเรคคอร์ด ควรโยนข้อยกเว้นตั้งแต่เนิ่น ๆ เพื่อบังคับใช้เงื่อนไขคงที่ของข้อมูล

record Email(String address) {
    Email {
        if (address == null || address.isBlank())
            throw new IllegalArgumentException("Email cannot be blank");
        if (!address.contains("@"))
            throw new IllegalArgumentException("Invalid email: " + address);
        address = address.toLowerCase().strip(); // normalize (Java 16+)
    }
}

Email e = new Email("  Alice@Example.com  ");
System.out.println(e.address()); // alice@example.com

try { new Email("not-an-email"); }
catch (IllegalArgumentException ex) { System.out.println(ex.getMessage()); }

การปรับรูปแบบข้อมูลในคอนสตรักเตอร์แบบย่อ

คุณสามารถแก้ไขตัวแปรคอมโพเนนต์ภายในคอนสตรักเตอร์แบบย่อ ก่อนที่ตัวแปรเหล่านั้นจะได้รับการกำหนดค่า วิธีนี้ช่วยปรับรูปแบบข้อมูลขณะสร้างออบเจ็กต์

record PersonName(String firstName, String lastName) {
    PersonName {
        firstName = capitalize(firstName);
        lastName  = capitalize(lastName);
    }

    private static String capitalize(String s) {
        if (s == null || s.isEmpty()) return s;
        return Character.toUpperCase(s.charAt(0)) +
               s.substring(1).toLowerCase();
    }

    public String fullName() { return firstName + " " + lastName; }
}

PersonName name = new PersonName("jOHN", "DOE");
System.out.println(name.fullName()); // John Doe

การคัดลอกเพื่อป้องกัน

สำหรับคอมโพเนนต์ที่เปลี่ยนแปลงได้ เช่น อาร์เรย์หรือคอลเลกชัน ให้คัดลอกข้อมูลเพื่อป้องกันภายในคอนสตรักเตอร์แบบย่อ เพื่อรักษาคุณสมบัติการเปลี่ยนแปลงไม่ได้

import java.util.*;

record Snapshot(List<String> items) {
    Snapshot {
        items = List.copyOf(items); // defensive copy — unmodifiable
    }
}

List<String> mutable = new ArrayList<>(List.of("a", "b", "c"));
Snapshot snap = new Snapshot(mutable);
mutable.add("d"); // doesn't affect snapshot
System.out.println(snap.items()); // [a, b, c]

try {
    snap.items().add("e"); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
    System.out.println("Snapshot is truly immutable!");
}

เรคคอร์ด Range พร้อมขอบเขต

เรคคอร์ด Range ภาคปฏิบัติที่รับประกันว่า min <= max และมีเมธอดยูทิลิตีที่เป็นประโยชน์

record Range(int min, int max) {
    Range {
        if (min > max) throw new IllegalArgumentException(
            "min (" + min + ") must be <= max (" + max + ")");
    }

    public boolean contains(int value) { return value >= min && value <= max; }
    public int size()  { return max - min; }
    public int clamp(int value) { return Math.max(min, Math.min(max, value)); }
}

Range valid = new Range(1, 10);
System.out.println(valid.contains(5));  // true
System.out.println(valid.clamp(15));    // 10
System.out.println(valid.size());       // 9

การเรียกต่อเนื่องของตรรกะในคอนสตรักเตอร์แบบย่อ

สำหรับการตรวจสอบที่ซับซ้อน ให้แยกเมธอดช่วยเหลือออกมา แล้วเรียกใช้จากคอนสตรักเตอร์แบบย่อ

record CreditCard(String number, String cvv, int expiryMonth, int expiryYear) {
    CreditCard {
        validateNumber(number);
        validateCvv(cvv);
        validateExpiry(expiryMonth, expiryYear);
        number = number.replaceAll("[^0-9]", ""); // strip spaces/dashes
    }

    private static void validateNumber(String n) {
        String digits = n.replaceAll("[^0-9]", "");
        if (digits.length() < 13 || digits.length() > 19)
            throw new IllegalArgumentException("Invalid card number length");
    }
    private static void validateCvv(String cvv) {
        if (!cvv.matches("[0-9]{3,4}"))
            throw new IllegalArgumentException("Invalid CVV");
    }
    private static void validateExpiry(int m, int y) {
        if (m < 1 || m > 12) throw new IllegalArgumentException("Invalid month");
        if (y < 2024)         throw new IllegalArgumentException("Card expired");
    }
}

รูปแบบคอนสตรักเตอร์แบบย่อหลายรูปแบบ

รูปแบบการตรวจสอบที่ใช้กันทั่วไปในคอนสตรักเตอร์แบบย่อ

record Percentage(double value) {
    Percentage {
        if (value < 0 || value > 100)
            throw new IllegalArgumentException(
                "Percentage must be 0-100, got: " + value);
        value = Math.round(value * 100.0) / 100.0; // round to 2 dp
    }

    public double asFraction() { return value / 100.0; }
}

Percentage tax = new Percentage(8.756);
System.out.println(tax.value());       // 8.76
System.out.println(tax.asFraction()); // 0.0876

คอนสตรักเตอร์ที่ไม่ใช่แบบหลัก

เรคคอร์ดสามารถมีคอนสตรักเตอร์เพิ่มเติมได้ แต่คอนสตรักเตอร์เหล่านั้นต้องส่งต่อไปยังคอนสตรักเตอร์หลักโดยใช้ this(...)

record Point(double x, double y) {
    // Non-canonical constructor: origin point
    Point() { this(0.0, 0.0); }

    // Non-canonical: polar coordinates
    static Point fromPolar(double r, double theta) {
        return new Point(r * Math.cos(theta), r * Math.sin(theta));
    }

    public double distance(Point other) {
        double dx = this.x - other.x;
        double dy = this.y - other.y;
        return Math.sqrt(dx*dx + dy*dy);
    }
}

Point origin = new Point();
Point p = Point.fromPolar(5, Math.PI/4);
System.out.printf("Distance: %.2f%n", origin.distance(p)); // 5.00

เรคคอร์ดคอลเลกชันที่เปลี่ยนแปลงไม่ได้

เรคคอร์ดที่เก็บสแนปชอตที่เปลี่ยนแปลงไม่ได้ของการตั้งค่าผู้ใช้ และตรวจสอบพร้อมปรับรูปแบบข้อมูลขณะสร้าง

import java.util.*;

record UserPreferences(String theme, Set<String> enabledFeatures, int fontSize) {
    private static final Set<String> VALID_THEMES = Set.of("light", "dark", "system");
    private static final Set<String> VALID_FEATURES = Set.of("ai", "beta", "analytics");

    UserPreferences {
        if (!VALID_THEMES.contains(theme))
            throw new IllegalArgumentException("Unknown theme: " + theme);
        if (!VALID_FEATURES.containsAll(enabledFeatures))
            throw new IllegalArgumentException("Unknown feature in: " + enabledFeatures);
        if (fontSize < 10 || fontSize > 24)
            throw new IllegalArgumentException("fontSize must be 10-24");
        enabledFeatures = Set.copyOf(enabledFeatures); // defensive copy
    }
}

ข้อจำกัดของคอนสตรักเตอร์แบบย่อ

สิ่งที่คุณไม่สามารถทำได้ในคอนสตรักเตอร์แบบย่อ:

  • ไม่สามารถกำหนดค่าคอมโพเนนต์อย่างชัดเจนได้ (ระบบจะกำหนดค่าให้อัตโนมัติหลังจบบล็อก)
  • ไม่สามารถเรียก this() หรือ super() ได้
  • การโยนข้อยกเว้นจะป้องกันไม่ให้กำหนดค่าคอมโพเนนต์ใด ๆ
record Safe(int value) {
    Safe {
        // CAN: validate and modify component variables
        if (value < 0) value = 0; // normalized to 0 if negative
        // value = this.value; // NOT NEEDED — assignment happens after block
    }
}

System.out.println(new Safe(-5).value());  // 0 (normalized)
System.out.println(new Safe(10).value());  // 10

ตรวจสอบความเข้าใจ

ในคอนสตรักเตอร์แบบย่อ การแก้ไขตัวแปรคอมโพเนนต์ที่คุณทำจะส่งผลอย่างไร

สรุปทบทวน: คอนสตรักเตอร์แบบย่อและการตรวจสอบข้อมูล

ประเด็นสำคัญ:

  • คอนสตรักเตอร์แบบย่อทำงานก่อนกำหนดค่าคอมโพเนนต์ จึงไม่ต้องกำหนดค่าอย่างชัดเจน
  • ใช้สำหรับตรวจสอบ ปรับรูปแบบ หรือคัดลอกคอมโพเนนต์เพื่อป้องกัน
  • แก้ไขตัวแปรคอมโพเนนต์เพื่อปรับรูปแบบค่า เช่น เปลี่ยนเป็นตัวพิมพ์เล็ก ตัดช่องว่าง หรือคัดลอก
  • โยน IllegalArgumentException สำหรับข้อมูลที่ไม่ถูกต้อง เพื่อบังคับใช้เงื่อนไขคงที่
  • ใช้ List.copyOf / Set.copyOf สำหรับคอมโพเนนต์คอลเลกชันที่เปลี่ยนแปลงได้
  • คอนสตรักเตอร์ที่ไม่ใช่แบบหลักต้องส่งต่อไปยังคอนสตรักเตอร์หลักด้วย this(...)

คำถามที่พบบ่อย

บทเรียน “ตัวสร้างแบบกระชับและการตรวจสอบความถูกต้อง” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ตัวสร้างแบบกระชับและการตรวจสอบความถูกต้อง” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ตัวสร้างแบบกระชับและการตรวจสอบความถูกต้อง”

เพิ่มตรรกะตรวจสอบความถูกต้องภายในตัวสร้างแบบกระชับ เพื่อรับรองความสมบูรณ์ของข้อมูล คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “ตัวสร้างแบบกระชับและการตรวจสอบความถูกต้อง” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เริ่มต้นใช้งาน Records
  2. ตัวสร้างแบบกระชับและการตรวจสอบความถูกต้อง
  3. เมธอดแบบกำหนดเองบน Records
  4. Records กับคลาสและ Lombok
← กลับไปที่ Java Academy