Kompaktowe konstruktory i walidacja
Dodawaj logikę walidacji wewnątrz kompaktowych konstruktorów, aby zapewnić integralność danych.
Kompaktowe konstruktory i walidacja to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
Konstruktory kompaktowe
Konstruktor kompaktowy rekordu jest wykonywany przed przypisaniem komponentów. Umożliwia sprawdzanie lub normalizowanie danych bez powtarzania przypisań komponentów.
Konstruktor standardowy a kompaktowy
Standardowy konstruktor kanoniczny jawnie przypisuje komponenty. Konstruktor kompaktowy pomija listę parametrów i przypisania — są one wykonywane automatycznie po zakończeniu jego ciała.
// 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
}
}Walidacja w konstruktorach kompaktowych
Konstruktory kompaktowe są standardowym sposobem walidowania danych rekordu. Należy wcześnie zgłaszać wyjątki, aby wymuszać zachowanie niezmienników.
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()); }Normalizacja w konstruktorach kompaktowych
W konstruktorze kompaktowym można modyfikować zmienne komponentów przed ich przypisaniem. Umożliwia to normalizowanie danych podczas tworzenia rekordu.
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 DoeKopiowanie defensywne
W przypadku zmiennych komponentów, takich jak tablice lub kolekcje, należy wykonać kopię defensywną w konstruktorze kompaktowym, aby zachować niezmienność.
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!");
}Rekord Range z ograniczeniami
Praktyczny rekord Range, który zapewnia spełnienie warunku min <= max i udostępnia przydatne metody pomocnicze.
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Łączenie logiki konstruktora kompaktowego
W przypadku złożonej walidacji należy wydzielić metody pomocnicze i wywoływać je z konstruktora kompaktowego.
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");
}
}Wiele wzorców konstruktorów kompaktowych
Typowe wzorce walidacji używane w konstruktorach kompaktowych.
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.0876Konstruktory niekanoniczne
Rekordy mogą mieć dodatkowe konstruktory, ale muszą one delegować do konstruktora kanonicznego za pomocą 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.00Rekord z niezmienną kolekcją
Rekord przechowujący niezmienny zrzut preferencji użytkownika, który podczas tworzenia rekordu sprawdza i normalizuje dane.
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
}
}Ograniczenia konstruktorów kompaktowych
Czego nie można robić w konstruktorze kompaktowym:
- Nie można jawnie przypisywać komponentów (są przypisywane automatycznie po zakończeniu bloku)
- Nie można wywoływać
this()anisuper() - Rzucenie wyjątku zapobiega przypisaniu wszystkich komponentów
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()); // 10Szybkie sprawdzenie
Co dzieje się ze zmianami zmiennych komponentów wprowadzonymi w konstruktorze kompaktowym?
Podsumowanie: konstruktory kompaktowe i walidacja
Najważniejsze informacje:
- Konstruktory kompaktowe są wykonywane przed przypisaniem komponentów — nie trzeba wykonywać jawnych przypisań
- Używaj ich do walidowania, normalizowania lub defensywnego kopiowania komponentów
- Modyfikuj zmienne komponentów, aby normalizować wartości (zamiana na małe litery, usunięcie białych znaków, kopiowanie)
- Rzucaj IllegalArgumentException dla nieprawidłowych danych, aby wymuszać zachowanie niezmienników
- Używaj List.copyOf / Set.copyOf dla zmiennych komponentów będących kolekcjami
- Konstruktory niekanoniczne muszą delegować do kanonicznego za pomocą this(...)
Często zadawane pytania
Czy lekcja „Kompaktowe konstruktory i walidacja” jest bezpłatna?
Tak — pełny tekst „Kompaktowe konstruktory i walidacja” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Kompaktowe konstruktory i walidacja”?
Dodawaj logikę walidacji wewnątrz kompaktowych konstruktorów, aby zapewnić integralność danych. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Kompaktowe konstruktory i walidacja”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Wprowadzenie do rekordów
- Kompaktowe konstruktory i walidacja
- Własne metody w rekordach
- Rekordy a klasy i Lombok