เมธอดแบบกำหนดเองบน Records
เพิ่มเมธอดอินสแตนซ์และเมธอดโรงงานแบบ static เพื่อเพิ่มความสามารถให้ records
เมธอดแบบกำหนดเองบน Records เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
เมธอดแบบกำหนดเองในเรคคอร์ด
เรคคอร์ดสามารถมีเมธอดอินสแตนซ์ เมธอดแบบคงที่ และฟิลด์แบบคงที่ได้ รวมถึงพฤติกรรมใด ๆ ที่คำนวณจากหรือเกี่ยวข้องกับคอมโพเนนต์ของเรคคอร์ด
เมธอดอินสแตนซ์ในเรคคอร์ด
เพิ่มเมธอดให้เรคคอร์ดเพื่อคำนวณค่าที่ได้จากข้อมูลเดิม หรือจัดเตรียมการดำเนินการที่เป็นประโยชน์โดยอาศัยคอมโพเนนต์
record Money(long cents, String currency) {
public double amount() { return cents / 100.0; }
public String display() { return String.format("%s %.2f", currency, amount()); }
public Money add(Money other) {
if (!currency.equals(other.currency))
throw new IllegalArgumentException("Currency mismatch");
return new Money(cents + other.cents, currency);
}
public Money multiply(int factor) { return new Money(cents * factor, currency); }
}
Money price = new Money(1999, "USD");
Money tax = new Money(160, "USD");
System.out.println(price.add(tax).display()); // USD 21.59เมธอดโรงงานแบบคงที่
เมธอดโรงงานแบบคงที่ช่วยให้สร้างเรคคอร์ดด้วยวิธีที่มีชื่อเรียกและอ่านเข้าใจง่าย โดยซ่อนคอนสตรักเตอร์โดยตรงเมื่อการเรียกใช้คอนสตรักเตอร์นั้นไม่ชัดเจน
import java.time.*;
record DateRange(LocalDate start, LocalDate end) {
DateRange { if (start.isAfter(end)) throw new IllegalArgumentException(); }
public static DateRange of(LocalDate start, LocalDate end) {
return new DateRange(start, end);
}
public static DateRange thisMonth() {
LocalDate now = LocalDate.now();
return new DateRange(now.withDayOfMonth(1),
now.withDayOfMonth(now.lengthOfMonth()));
}
public long durationDays() {
return ChronoUnit.DAYS.between(start, end) + 1;
}
}
System.out.println(DateRange.thisMonth().durationDays());เมธอดตรวจเงื่อนไข
เรคคอร์ดมักเปิดเผยเมธอดตรวจเงื่อนไขที่คืนค่าแบบบูลีน เพื่อใช้ตรวจสอบเงื่อนไขของข้อมูลที่จัดเก็บ
record User(String email, String plan, boolean emailVerified) {
public boolean isPro() { return "PRO".equals(plan); }
public boolean canPublish() { return isPro() && emailVerified; }
public boolean isFree() { return "FREE".equals(plan); }
public User withPlan(String newPlan) {
return new User(email, newPlan, emailVerified); // "update"
}
}
User u = new User("alice@example.com", "FREE", true);
System.out.println(u.canPublish()); // false
User upgraded = u.withPlan("PRO");
System.out.println(upgraded.canPublish()); // trueเมธอดคัดลอกพร้อมแก้ไข
เนื่องจากเรคคอร์ดเปลี่ยนแปลงไม่ได้ การ "อัปเดต" จึงหมายถึงการสร้างเรคคอร์ดตัวใหม่ เมธอดคัดลอกพร้อมแก้ไขใช้รูปแบบ withX(newValue)
record ServerConfig(String host, int port, boolean ssl, int timeout) {
public ServerConfig withHost(String h) { return new ServerConfig(h, port, ssl, timeout); }
public ServerConfig withPort(int p) { return new ServerConfig(host, p, ssl, timeout); }
public ServerConfig withSsl(boolean s) { return new ServerConfig(host, port, s, timeout); }
public ServerConfig withTimeout(int t) { return new ServerConfig(host, port, ssl, t); }
}
ServerConfig dev = new ServerConfig("localhost", 8080, false, 30);
ServerConfig prod = dev
.withHost("api.example.com")
.withPort(443)
.withSsl(true)
.withTimeout(60);
System.out.println(prod);เรคคอร์ดที่ใช้งานอินเทอร์เฟซเชิงฟังก์ชัน
เรคคอร์ดที่ใช้งานอินเทอร์เฟซเชิงฟังก์ชันด้วย สามารถส่งผ่านโดยตรงเพื่อใช้แทนแลมบ์ดาได้
import java.util.function.*;
record Validator<T>(Predicate<T> rule, String message)
implements Predicate<T> {
public boolean test(T value) { return rule.test(value); }
public String validate(T value) {
return test(value) ? null : message;
}
}
Validator<String> notEmpty = new Validator<>(
s -> !s.isBlank(), "Must not be blank");
Validator<String> validEmail = new Validator<>(
s -> s.contains("@"), "Invalid email");
System.out.println(notEmpty.validate("")); // Must not be blank
System.out.println(validEmail.validate("a@b.c")); // null (valid)เมธอดรวมข้อมูล
เรคคอร์ดที่เก็บคอลเลกชันสามารถเปิดเผยเมธอดรวมข้อมูลที่ทำงานบน stream ได้
import java.util.*;
record SalesReport(String region, List<Double> dailySales) {
SalesReport { dailySales = List.copyOf(dailySales); }
public double total() { return dailySales.stream().mapToDouble(Double::doubleValue).sum(); }
public double average() { return dailySales.stream().mapToDouble(Double::doubleValue).average().orElse(0); }
public double max() { return dailySales.stream().mapToDouble(Double::doubleValue).max().orElse(0); }
public int days() { return dailySales.size(); }
}
SalesReport r = new SalesReport("North", List.of(1200.0, 1450.0, 980.0, 1600.0));
System.out.printf("Total: %.0f, Avg: %.0f, Max: %.0f%n", r.total(), r.average(), r.max());
// Total: 5230, Avg: 1307, Max: 1600การเขียนทับ toString แบบกำหนดเอง
แม้ toString ที่สร้างโดยอัตโนมัติจะมีประโยชน์สำหรับการดีบัก แต่คุณอาจต้องการเขียนทับเพื่อใช้แสดงผลแก่ผู้ใช้
record Temperature(double celsius) {
@Override
public String toString() {
return String.format("%.1f\u00b0C / %.1f\u00b0F",
celsius, toFahrenheit());
}
public double toFahrenheit() { return celsius * 9.0/5.0 + 32; }
public double toKelvin() { return celsius + 273.15; }
public static Temperature fromFahrenheit(double f) {
return new Temperature((f - 32) * 5.0/9.0);
}
}
Temperature boiling = new Temperature(100.0);
System.out.println(boiling); // 100.0°C / 212.0°Fเรคคอร์ดในฐานะออบเจ็กต์ค่าใน DDD
ใน DDD เรคคอร์ดสอดคล้องกับออบเจ็กต์ค่า (Value Objects) ได้อย่างเป็นธรรมชาติ ซึ่งเป็นชนิดข้อมูลที่กำหนดโดยแอตทริบิวต์ ไม่ใช่ด้วยอัตลักษณ์
// Value objects in a banking domain
record AccountId(String value) {
AccountId { if (!value.matches("ACC-[0-9]{8}")) throw new IllegalArgumentException(); }
}
record Amount(long cents, String currency) {
public static Amount usd(long cents) { return new Amount(cents, "USD"); }
public boolean isPositive() { return cents > 0; }
}
record TransactionId(java.util.UUID value) {
public static TransactionId generate() {
return new TransactionId(java.util.UUID.randomUUID());
}
}
AccountId id = new AccountId("ACC-12345678");
Amount amount = Amount.usd(5000);
TransactionId txId = TransactionId.generate();
System.out.println(id + " " + amount + " " + txId);การเปรียบเทียบเรคคอร์ดด้วย Comparator
เรคคอร์ดสามารถจัดเรียงได้โดยใช้ Comparator.comparing ร่วมกับการอ้างอิงเมธอดที่ชี้ไปยังเมธอดเข้าถึงข้อมูล
import java.util.*;
record Employee(String name, String dept, double salary) {}
List<Employee> employees = List.of(
new Employee("Alice", "Engineering", 95000),
new Employee("Bob", "Marketing", 72000),
new Employee("Charlie", "Engineering", 105000),
new Employee("Diana", "Marketing", 81000)
);
// Sort by dept, then salary descending
employees.stream()
.sorted(Comparator.comparing(Employee::dept)
.thenComparing(Comparator.comparingDouble(Employee::salary).reversed()))
.forEach(e -> System.out.printf("%-10s %-15s %.0f%n",
e.name(), e.dept(), e.salary()));เมธอดยูทิลิตีแบบคงที่ในเรคคอร์ด
เรคคอร์ดสามารถมีเมธอดแบบคงที่ที่ทำงานกับอินสแตนซ์ของเรคคอร์ดหลายตัว ซึ่งมีประโยชน์สำหรับการแปลงและการเปรียบเทียบ
import java.util.*;
import java.util.stream.*;
record Product(String id, String category, double price) {
public static Map<String, DoubleSummaryStatistics> statsByCategory(
List<Product> products) {
return products.stream().collect(
Collectors.groupingBy(Product::category,
Collectors.summarizingDouble(Product::price)));
}
public static Optional<Product> cheapest(List<Product> products) {
return products.stream()
.min(Comparator.comparingDouble(Product::price));
}
}ตรวจสอบความเข้าใจ
คุณต้องการ "อัปเดต" ฟิลด์ของเรคคอร์ด แนวทางที่ถูกต้องคืออะไร
สรุปทบทวน: เมธอดแบบกำหนดเองในเรคคอร์ด
ประเด็นสำคัญ:
- เรคคอร์ดสามารถมีเมธอดอินสแตนซ์ เมธอดแบบคงที่ และฟิลด์แบบคงที่
- เพิ่มคุณสมบัติที่คำนวณได้ในรูปแบบเมธอด เช่น area(), ผลรวม() และ display()
- ใช้เมธอดโรงงานแบบคงที่เพื่อสร้างคอนสตรักเตอร์ที่มีชื่ออ่านเข้าใจง่าย
- ใช้งานเมธอดคัดลอกพร้อมแก้ไข (withX) สำหรับการอัปเดตแบบเปลี่ยนแปลงไม่ได้
- เขียนทับ toString() เพื่อแสดงผลแก่ผู้ใช้ แทนการแสดงผลสำหรับการดีบัก
- เรคคอร์ดสอดคล้องกับออบเจ็กต์ค่าใน DDD ได้อย่างเป็นธรรมชาติ
คำถามที่พบบ่อย
บทเรียน “เมธอดแบบกำหนดเองบน Records” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “เมธอดแบบกำหนดเองบน Records” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “เมธอดแบบกำหนดเองบน Records”
เพิ่มเมธอดอินสแตนซ์และเมธอดโรงงานแบบ static เพื่อเพิ่มความสามารถให้ records คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “เมธอดแบบกำหนดเองบน Records” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เริ่มต้นใช้งาน Records
- ตัวสร้างแบบกระชับและการตรวจสอบความถูกต้อง
- เมธอดแบบกำหนดเองบน Records
- Records กับคลาสและ Lombok