JavaRush /Java Blog /Random-IT /Pausa caffè #230. Cosa sono i record in Java e come funzi...

Pausa caffè #230. Cosa sono i record in Java e come funzionano?

Pubblicato nel gruppo Random-IT
Fonte: JavaTechOnline Questo articolo fornisce uno sguardo approfondito al concetto di record in Java con esempi, inclusa la loro sintassi, come crearli e come utilizzarli. Pausa caffè #230.  Cosa sono i record in Java e come funzionano - 1I record in Java sono una delle fantastiche funzionalità introdotte per la prima volta in Java 14 come funzionalità di anteprima e infine rese disponibili nella versione Java 17. Molti sviluppatori lo utilizzano attivamente, il che li aiuta a ridurre con successo un'enorme quantità di codice standard. Inoltre, grazie ai record, non è necessario scrivere una sola riga di codice per rendere immutabile una classe.

Quando utilizzare Record in Java?

Se desideri trasferire dati immutabili tra diversi livelli della tua applicazione, utilizzare Record può essere una buona scelta. Per impostazione predefinita, i record in Java sono immutabili, il che significa che non possiamo modificare le loro proprietà una volta creati. Di conseguenza, questo ci aiuta a evitare errori e migliora l’affidabilità del codice. In poche parole, utilizzando Record in Java, possiamo generare automaticamente classi.

Dove posso utilizzare Record in Java?

In generale, possiamo utilizzare i record in qualsiasi situazione in cui dobbiamo dichiarare semplici contenitori di dati con proprietà immutabili e metodi generati automaticamente. Ad esempio, di seguito sono riportati alcuni casi d'uso in cui i record possono essere utili: Oggetti di trasferimento dati (DTO): possiamo utilizzare Record per dichiarare semplici oggetti di trasferimento dati che contengono dati. Ciò è utile quando si trasferiscono dati tra diversi livelli di applicazione, ad esempio tra il livello di servizio e il livello di database. Oggetti di configurazione : il record può essere utilizzato per dichiarare oggetti di configurazione che contengono un insieme di proprietà di configurazione per un'applicazione o un modulo. Questi oggetti in genere hanno proprietà immutabili, che li rendono thread-safe e facili da usare. Oggetti di valore. Il record può essere utilizzato per dichiarare oggetti valore che contengono un insieme di valori che rappresentano un concetto specifico o un modello di dominio. Risposte API : quando si crea un'API REST, i dati vengono generalmente restituiti sotto forma di JSON o XML. In questi casi, potrebbe essere necessario definire una struttura dati semplice che rappresenti la risposta API. I record sono ideali per questo perché consentono di definire una struttura dati leggera e immutabile che può essere facilmente serializzata in JSON o XML. Dati di test. Quando si scrivono unit test, spesso è necessario creare dati di test che rappresentino uno scenario specifico. In questi casi, potrebbe essere necessario definire una struttura dati semplice che rappresenti i dati del test. I record possono essere ideali per questo perché ci consentono di definire una struttura dati leggera e immutabile con un codice standard minimo. Oggetti simili a tuple : i record possono essere utilizzati per dichiarare oggetti simili a tuple che contengono un numero fisso di valori associati. Ciò può essere utile quando si restituiscono più valori da un metodo o quando si lavora con raccolte di valori correlati.

Cos'è la registrazione in Java?

Record in Java è una classe progettata per archiviare dati. È simile a una classe Java tradizionale, ma è più leggera e presenta alcune caratteristiche uniche. I record sono immutabili per impostazione predefinita, il che significa che il loro stato non può essere modificato una volta creati. Ciò li rende ideali per archiviare dati immutabili, come parametri di configurazione o valori restituiti da una query sul database. È anche un modo per creare un tipo di dati personalizzato costituito da un insieme di campi o variabili, nonché metodi per accedere e modificare tali campi. La registrazione in Java semplifica il lavoro con i dati riducendo la quantità di codice standard che gli sviluppatori devono scrivere più e più volte. La sintassi per creare una voce in Java è:
record Record_Name(Fields....)

Come creare e utilizzare Record in Java con esempi?

Vediamo come creare e utilizzare un record in Java a livello di codice.

Creazione di un record

La creazione di un record a livello di codice non è molto simile alla creazione di una normale classe in Java. Invece di class usiamo la parola chiave record . È inoltre necessario dichiarare i campi con i tipi di dati tra parentesi del nome del record. Ecco un esempio di codice che dimostra come creare una voce in Java:
public record Book(String name, double price) { }
In questo esempio, abbiamo creato un record chiamato Libro con due campi: nome e prezzo . La parola chiave public indica che è possibile accedere a questa voce all'esterno del pacchetto in cui è definita.

Utilizzando Registra

Per utilizzare un record in Java, possiamo istanziarlo utilizzando la parola chiave new, proprio come facciamo con una classe normale. Ecco un esempio:
Book book = new Book( "Core Java" , 324.25);
Qui viene creata una nuova istanza del record Book con il campo del nome impostato su Core Java e il campo del prezzo impostato su 324.25 . Una volta creato un record, è possibile accedere ai suoi campi utilizzando il nome del campo stesso. Non esistono metodi get o set. Il nome del campo diventa invece il nome del metodo.
String name = book.name();

double price = book.price();
Qui vediamo il valore dei campi nome e prezzo recuperati dal record Libro . Oltre ai campi, i record dispongono anche di alcuni metodi integrati che è possibile utilizzare per manipolarli. Ad esempio, toString() , equals() e hashCode() . Ricorda che i record Java sono immutabili per impostazione predefinita, il che significa che una volta creati, il loro stato non può essere modificato. Diamo un'occhiata a un altro esempio di come creare e utilizzare i record in Java. Prendiamo un caso in cui abbiamo bisogno di un record per archiviare informazioni su uno studente.
public record Student(String name, int age, String subject) {}
Questo crea un record chiamato Studente con tre campi: nome , età e materia . Possiamo creare un'istanza di questa voce come segue:
Student student = new Student("John Smith", 20, "Computer Science");
Possiamo quindi ottenere i valori del campo utilizzando il nome del campo:
String name = student.name();
int age = student.age();
String subject= student.subject();

Come appare il Record dopo la compilazione?

Poiché Record è solo un tipo speciale di classe, il compilatore la converte anche in una classe normale, ma con alcune restrizioni e differenze. Quando il compilatore converte un record (file Java) in bytecode dopo il processo di compilazione, il file .class generato contiene alcune dichiarazioni aggiuntive della classe Record . Ad esempio, di seguito è riportato il bytecode generato per la voce Studente dal compilatore Java:
record Student(String name, int age) {   }

Scrittura nel file .class (dopo la compilazione)

Possiamo anche trovare la classe convertita di seguito se utilizziamo lo strumento javap e applichiamo il comando seguente dalla riga di comando. È importante notare che la riga di comando Java include lo strumento javap , che puoi utilizzare per visualizzare informazioni su campi, costruttori e metodi di un file di classe. >Javap Conclusione dello studente: se controlliamo attentamente il bytecode, potremmo avere alcune osservazioni:
  • Il compilatore ha sostituito la parola chiave Record con class .
  • Il compilatore ha dichiarato la classe final . Ciò indica che questa classe non può essere estesa. Ciò significa anche che non può essere ereditato ed è di natura immutabile.
  • La classe convertita estende java.lang.Record . Ciò indica che tutti i record sono una sottoclasse della classe Record definita nel pacchetto java.lang .
  • Il compilatore aggiunge un costruttore con parametri.
  • Il compilatore ha generato automaticamente i metodi toString() , hashCode() e equals() .
  • Il compilatore ha aggiunto metodi per accedere ai campi. Presta attenzione alla convenzione di denominazione dei metodi: sono esattamente gli stessi dei nomi dei campi, non dovrebbero esserci get o set prima dei nomi dei campi .

Campi nei record

I record in Java definiscono il loro stato utilizzando una serie di campi, ciascuno con un nome e un tipo diverso. I campi di un record sono dichiarati nell'intestazione del record. Per esempio:
public record Person(String name, int age) {}
Questa voce ha due campi: nome di tipo String ed età di tipo int . I campi di un record sono implicitamente definitivi e non possono essere riassegnati dopo la creazione del record. Possiamo aggiungere un nuovo campo, ma questo non è raccomandato. Un nuovo campo aggiunto a un record deve essere statico. Per esempio:
public record Person(String name, int age) {

   static String sex;
}

Costruttori nei record

Come i costruttori di classi tradizionali, i costruttori di record vengono utilizzati per creare istanze di record. Records ha due concetti di costruttori: il costruttore canonico e il costruttore compatto . Il costruttore compatto fornisce un modo più conciso per inizializzare le variabili di stato in un record, mentre il costruttore canonico fornisce un modo più tradizionale con maggiore flessibilità.

Costruttore canonico

Il compilatore Java predefinito ci fornisce un costruttore di tutti gli argomenti (costruttore di tutti i campi) che assegna i suoi argomenti ai campi corrispondenti. È noto come costruttore canonico. Possiamo anche aggiungere logica aziendale come istruzioni condizionali per convalidare i dati. Di seguito è riportato un esempio:
public record Person(String name, int age) {

       public Person(String name, int age) {
           if (age < 18) {
              throw new IllegalArgumentException("You are not allowed to participate in general elections");
           }
      }
}

Progettista compatto

I costruttori compatti ignorano tutti gli argomenti, comprese le parentesi. I campi corrispondenti vengono assegnati automaticamente. Ad esempio, il codice seguente dimostra il concetto di costruttore compatto in Records :
public record Person(String name, int age) {

      public Person {
          if (age < 18) {
              throw new IllegalArgumentException("You are not allowed to participate in general elections");
          }
     }
}
Oltre al costruttore compatto, puoi definire costruttori regolari in Record , proprio come in una classe normale. Tuttavia, è necessario assicurarsi che tutti i costruttori inizializzino tutti i campi del record.

Metodi nei record

I record in Java generano automaticamente una serie di metodi per ciascun campo nel record. Questi metodi sono chiamati metodi di accesso e hanno lo stesso nome del campo a cui sono associati. Ad esempio, se un record ha un campo denominato price , avrà automaticamente un metodo chiamato price() che restituisce il valore del campo price . Oltre ai metodi accessori generati automaticamente, possiamo anche definire i nostri metodi in una voce, proprio come in una normale classe. Per esempio:
public record Person(String name, int age) {
   public void sayHello() {
      System.out.println("Hello, my name is " + name);
   }
}
Questa voce ha un metodo sayHello() che stampa un saluto utilizzando il campo nome .

In che modo Record aiuta a ridurre il codice standard

Diamo un'occhiata a un semplice esempio per vedere come le notazioni Java possono aiutare a eliminare il codice standard. Diciamo di avere una classe chiamata Persona che rappresenta una persona con nome, età e indirizzo email. Questo è il modo in cui definiamo una classe in modo tradizionale. Codice senza utilizzare Record :
public class Person {

    private String name;
    private int age;
    private String email;

    public Person(String name, int age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }

    public String getName() {

       return name;
    }

    public int getAge() {
       return age;
    }

    publicString getEmail() {
       return email;
    }

    public void setName(String name) {
       this.name = name;
    }

    public voidsetAge(int age) {
       this.age = age;
    }

    public void setEmail(String email) {
       this.email = email;
    }

    @Override
    public String toString() {
       return "Person{" +
         "name='" + name + '\'' +
         ", age=" + age +
         ", email='" + email + '\'' +
      '}';
    }
}
Come possiamo vedere, questa classe richiede molto codice standard per definire i campi, il costruttore, i getter, i setter e il metodo toString() . Inoltre, supponiamo di voler rendere questa classe immutabile. Per fare ciò dovremo eseguire alcuni passaggi aggiuntivi come:
  • Dichiarare la classe come finale in modo che non possa essere estesa.
  • Dichiara tutti i campi private e final in modo che non possano essere modificati all'esterno del costruttore.
  • Non fornire alcun metodo setter per i campi.
  • Se uno qualsiasi dei campi è modificabile, dovresti restituirne una copia invece di restituire l'oggetto originale.
Codice utilizzando Record :
public record Person(String name, int age, String email) {}
È tutto! Con una sola riga di codice, abbiamo definito una classe che ha gli stessi campi, costruttore, getter, setter e metodo toString() di una classe tradizionale. La sintassi Record si prende cura di tutto il codice standard per noi. Dall'esempio precedente, è chiaro che l'utilizzo dei record in Java può aiutare a eliminare il codice standard fornendo una sintassi più concisa per definire le classi con un insieme fisso di campi. Per definire e utilizzare i record è necessario meno codice rispetto all'approccio tradizionale e i record forniscono accesso diretto ai campi utilizzando metodi per aggiornare i campi. Ciò rende il codice più leggibile, gestibile e meno soggetto a errori. Inoltre, con Record syntax , non abbiamo bisogno di fare nulla in più per rendere la classe immutabile. Per impostazione predefinita, tutti i campi di un record sono definitivi e la classe del record stessa è immutabile. Pertanto, creare una classe immutabile utilizzando la sintassi di scrittura è molto più semplice e richiede meno codice rispetto all'approccio tradizionale. Con i record, non è necessario dichiarare i campi come final , fornire un costruttore che inizializzi i campi o fornire getter per tutti i campi.

Classi di record comuni

Java può anche definire classi Records generiche . Una classe di voce generica è una classe di voce che dispone di uno o più parametri di tipo. Ecco un esempio:
public record Pair<T, U>(T first, U second) {}
In questo esempio , Pair è una classe di record generica che accetta due parametri di tipo T e U. Possiamo creare un'istanza di questo record come segue:
Pair<String, Integer>pair = new Pair<>( "Hello" , 123);

Classe nidificata all'interno di Record

È inoltre possibile definire classi e interfacce nidificate all'interno di una voce. Ciò è utile per raggruppare classi e interfacce correlate e può aiutare a migliorare l'organizzazione e la manutenibilità della codebase. Ecco un esempio di una voce contenente una classe nidificata:
public record Person(String name, int age, Contact contact){

    public static class Contact {

       private final String email;
       private final String phone;

       public Contact(String email, String phone){
           this.email = email;
           this.phone = phone;
       }

       public String getEmail(){
          return email;
       }

       public String getPhone(){
          return phone;
       }
    }
}
In questo esempio, Person è una voce contenente una classe Contact nidificata . A sua volta, Contact è una classe nidificata statica che contiene due campi finali privati: indirizzo email e telefono. Ha anche un costruttore che accetta un'e-mail e un numero di telefono e due metodi getter: getEmail() e getPhone() . Possiamo creare un'istanza Person come questa:
Person person = new Person("John",30, new Person.Contact("john@example.com", "123-456-7890"));
In questo esempio, abbiamo creato un nuovo oggetto Persona denominato John , età 30 anni, e un nuovo oggetto Contatto con email john@example.com e telefono 123-456-7890 .

Interfaccia nidificata all'interno di Record

Ecco una voce di esempio contenente un'interfaccia nidificata:
public record Book(String title, String author, Edition edition){
    public interface Edition{
       String getName();
   }
}
In questo esempio, Book è la voce contenente l' interfaccia Edition nidificata . A sua volta, Edition è un'interfaccia che definisce un singolo metodo getName() . Possiamo creare un'istanza del libro come segue:
Book book = new Book("The Hitchhiker's Guide to the Galaxy", "Douglas Adams", new Book.Edition() {

   public String getName() {

      return "Science Fiction";
   }
});
In questo esempio, creiamo un nuovo oggetto Libro con il titolo Guida galattica per autostoppisti di Douglas Adams e una nuova implementazione anonima dell'interfaccia Edition che restituisce il nome Science Fiction quando viene chiamato il metodo getName() .

Cos'altro può fare Records?

  • Le voci possono definire costruttori personalizzati. I record supportano costruttori con parametri, che possono chiamare un costruttore predefinito con i parametri forniti nei relativi corpi. Inoltre, i record supportano anche costruttori compatti, che sono simili ai costruttori predefiniti ma possono includere funzionalità aggiuntive come i controlli nel corpo del costruttore.
  • Come qualsiasi altra classe in Java, Record può definire e utilizzare metodi di istanza. Ciò significa che possiamo creare e chiamare metodi specifici per la classe di registrazione.
  • In Record , la definizione di variabili di istanza come membri della classe non è consentita perché possono essere specificate solo come parametri del costruttore. Tuttavia, i record supportano campi statici e metodi statici, che possono essere utilizzati per archiviare e accedere ai dati comuni a tutte le istanze della classe di record.

Un record può implementare interfacce?

Sì, scrivere in Java può implementare le interfacce. Ad esempio, il codice seguente dimostra il concetto:
public interface Printable {
   void print();
}
public record Person(String name, int age) implements Printable {
   public void print() {
      System.out.println("Name: " + name + ", Age: " + age);
   }
}
Qui abbiamo definito un'interfaccia stampabile con un singolo metodo print() . Abbiamo anche definito una voce Persona che implementa l' interfaccia Printable . Il record Persona ha due campi: nome ed età e sovrascrive il metodo di stampa dell'interfaccia Printable per stampare i valori di questi campi. Possiamo istanziare una voce Persona e chiamare il suo metodo di stampa in questo modo:
Person person = new Person("John", 30);
person.print();
Verrà visualizzato Nome: John, Età: 30 sulla console . Come mostrato nell'esempio, i record Java possono implementare interfacce proprio come le classi normali. Ciò può essere utile per aggiungere un comportamento a una voce o per garantire che una voce sia conforme a un contratto definito da un'interfaccia.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION