0Pricing
Java Academy · Lezione

Costruttori compatti e validazione

Aggiunga la logica di validazione all'interno dei costruttori compatti per garantire l'integrità dei dati.

Costruttori compatti e validazione è una lezione Java Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Java Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Java Academy include 4 lezioni in totale.

Costruttori compatti

Un costruttore compatto in un record viene eseguito prima dell'assegnazione dei componenti. Consente di convalidare o normalizzare i dati senza ripetere le assegnazioni dei componenti.

Costruttore standard rispetto a costruttore compatto

Il costruttore canonico standard assegna esplicitamente i componenti. Il costruttore compatto omette l'elenco dei parametri e le assegnazioni, che vengono eseguite automaticamente dopo il corpo del costruttore.

// 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
    }
}

Convalida nei costruttori compatti

I costruttori compatti sono il modo standard per convalidare i dati dei record. Generi eccezioni tempestivamente per imporre gli invarianti.

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()); }

Normalizzazione nei costruttori compatti

È possibile modificare le variabili dei componenti all'interno di un costruttore compatto prima che vengano assegnate. In questo modo i dati vengono normalizzati durante la costruzione.

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

Copia difensiva

Per i componenti mutabili, come array o collezioni, esegua una copia difensiva nel costruttore compatto per preservare l'immutabilità.

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!");
}

Record Range con limiti

Un record Range pratico che garantisce min <= max e fornisce utili metodi di utilità.

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

Concatenare la logica del costruttore compatto

Per convalide complesse, estragga i metodi di supporto e li richiami dal costruttore compatto.

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");
    }
}

Più pattern per i costruttori compatti

Pattern di convalida comuni utilizzati nei costruttori compatti.

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

Costruttori non canonici

I record possono avere costruttori aggiuntivi, ma questi devono delegare al costruttore canonico utilizzando 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

Record per collezioni immutabili

Un record che contiene un'istantanea immutabile delle preferenze dell'utente e le convalida e normalizza durante la costruzione.

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
    }
}

Limitazioni dei costruttori compatti

Operazioni non consentite in un costruttore compatto:

  • Non è possibile assegnare esplicitamente i componenti (vengono assegnati automaticamente dopo il blocco)
  • Non è possibile chiamare this() o super()
  • Il lancio di un'eccezione impedisce tutte le assegnazioni dei componenti
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

Verifica rapida

In un costruttore compatto, cosa succede alle modifiche apportate alle variabili dei componenti?

Riepilogo: costruttori compatti e convalida

Punti chiave:

  • I costruttori compatti vengono eseguiti prima dell'assegnazione dei componenti: non servono assegnazioni esplicite
  • Li utilizzi per convalidare, normalizzare o copiare difensivamente i componenti
  • Modifichi le variabili dei componenti per normalizzare i valori (minuscole, trim, copia)
  • Generi IllegalArgumentException per i dati non validi, così da imporre gli invarianti
  • Utilizzi List.copyOf / Set.copyOf per i componenti che sono collezioni mutabili
  • I costruttori non canonici devono delegare a quello canonico con this(...)

Domande Frequenti

La lezione «Costruttori compatti e validazione» è gratuita?

Sì — il testo completo di «Costruttori compatti e validazione» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Java Academy, passa a CoddyKit PRO. Il corso Java Academy include 4 lezioni in totale.

Cosa imparerò in «Costruttori compatti e validazione»?

Aggiunga la logica di validazione all'interno dei costruttori compatti per garantire l'integrità dei dati. Eserciti Java Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Java Academy?

Non è richiesta alcuna esperienza precedente. Java Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Costruttori compatti e validazione»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Java Academy?

Sì. Ogni lezione Java Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Introduzione ai record
  2. Costruttori compatti e validazione
  3. Metodi personalizzati nei record
  4. Record, classi e Lombok a confronto
← Torna a Java Academy